1. 程式人生 > >Spring各種依賴注入註解的區別

Spring各種依賴注入註解的區別

Spring對於Bean的依賴注入,支援多種註解方式:

  1. @Resource
    • javax.annotation
    • JSR250 (Common Annotations for Java)
  2. @Inject
    • javax.inject
    • JSR330 (Dependency Injection for Java)
  3. @Autowired
    • org.springframework.bean.factory
    • Spring

直觀上看起來,@Autowired是Spring提供的註解,其他幾個都是JDK本身內建的註解,Spring對這些註解也進行了支援。但是使用起來這三者到底有什麼區別呢?筆者經過方法的測試,發現一些有意思的特性。總結如下:

1. @Autowired有個required屬性,可以配置為false,這種情況下如果沒有找到對應的bean是不會拋異常的。@Inject和@Resource沒有提供對應的配置,所以必須找到否則會拋異常。

2. @Autowired和@Inject基本是一樣的,因為兩者都是使用AutowiredAnnotationBeanPostProcessor來處理依賴注入。但是@Resource是個例外,它使用的是CommonAnnotationBeanPostProcessor來處理依賴注入。當然,兩者都是BeanPostProcessor

@Autowired和@Inject

  • 預設 autowired by type
  • 可以 通過@Qualifier 顯式指定 autowired by qualifier name。
  • 如果 autowired by type 失敗(找不到或者找到多個實現),則退化為autowired by field name

@Resource

  • 預設 autowired by field name
  • 如果 autowired by field name失敗,會退化為 autowired by type
  • 可以 通過@Qualifier 顯式指定 autowired by qualifier name
  • 如果 autowired by qualifier name失敗,會退化為 autowired by field name。但是這時候如果 autowired by field name失敗,就不會再退化為autowired by type了。
TIPS Qualified name VS Bean name

在Spring設計中,Qualified name並不等同於Bean name,後者必須是唯一的,但是前者類似於tag或者group的作用,對特定的bean進行分類。可以達到getByTag(group)的效果。對於XML配置的bean,可以通過id屬性指定bean name(如果沒有指定,預設使用類名首字母小寫),通過<qualifier>標籤指定qualifier name:

<bean id="lamborghini" class="me.arganzheng.study.spring.autowired.Lamborghini">
    <qualifier value="luxury"/>
    <!-- inject any dependencies required by this bean -->
</bean>

如果是通過註解方式,那麼可以通過@Qualifier註解指定qualifier name,通過@Named或者@Component(@Service,@Repository等)的value值指定bean name:

@Component("lamborghini")
@Qualifier("luxury")
public class Lamborghini implements Car {

}

或者

@Component
@Named("lamborghini")
@Qualifier("luxury")
public class Lamborghini implements Car {

}   

同樣,如果沒有指定bean name,那麼Spring會預設是用類名首字母小寫(Lamborghini=>lamborghini)。

3. 通過Anotation注入依賴的方式在XML注入方式之前進行。如果對同一個bean的依賴同時使用了兩種注入方式,那麼XML的優先。但是不同擔心通過Anotation注入的依賴沒法注入XML中配置的bean,依賴注入是在bean的註冊之後進行的。

4. 目前的autowired by type方式(筆者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor實現都是有"bug"的,也就是說@Autowired和@Inject都是有坑的(稱之為坑,不稱之為bug是因為貌似是故意的。。)。這是來源於線上的一個bug,也是這邊文章的寫作原因。現場如下:

application-context.xml中有如下定義:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

    <context:annotation-config />

    <context:component-scan base-package="me.arganzheng.study" />

    <util:constant id="en"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN" />
    <util:constant id="ja"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.JP" />
    <util:constant id="ind"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.IND" />
    <util:constant id="pt"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.PT" />
    <util:constant id="th"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.TH" />
    <util:constant id="ar"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.AR" />
    <util:constant id="en-rIn"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN_RIN" />

    <util:map id="languageChangesMap" key-type="java.lang.String"
        value-type="java.lang.String">
        <entry key="pt" value="pt" />
        <entry key="br" value="pt" />
        <entry key="jp" value="ja" />
        <entry key="ja" value="ja" />
        <entry key="ind" value="ind" />
        <entry key="id" value="ind" />
        <entry key="en-rin" value="en-rIn" />
        <entry key="in" value="en-rIn" />
        <entry key="en" value="en" />
        <entry key="gb" value="en" />
        <entry key="th" value="th" />
        <entry key="ar" value="ar" />
        <entry key="eg" value="ar" />
    </util:map>

</beans>    

其中static-field應用的常量定義在如下類中:

package me.arganzheng.study.spring.autowired;

public interface Constants {

    public interface Language {
        public static final String EN = "CommonConstants.LANG_ENGLISH";
        public static final String JP = "CommonConstants.LANG_JAPANESE";
        public static final String IND = "CommonConstants.LANG_INDONESIAN";
        public static final String PT = "CommonConstants.LANG_PORTUGUESE";
        public static final String TH = "CommonConstants.LANG_THAI";
        public static final String EN_RIN = "CommonConstants.LANG_ENGLISH_INDIA";
        public static final String AR = "CommonConstants.LANG_Arabic";
    }

}

然後如果我們在程式碼中如下宣告依賴:

public class AutowiredTest extends BaseSpringTestCase {

    @Autowired
    private Map<String, String> languageChangesMap;

    @Test
    public void testAutowired() {
        notNull(languageChangesMap);
        System.out.println(languageChangesMap.getClass().getSimpleName());
        System.out.println(languageChangesMap);
    }

}

Guess what,詭異的事情發生了!

執行結果如下:

LinkedHashMap
{en=CommonConstants.LANG_ENGLISH, ja=CommonConstants.LANG_JAPANESE, ind=CommonConstants.LANG_INDONESIAN, pt=CommonConstants.LANG_PORTUGUESE, th=CommonConstants.LANG_THAI, ar=CommonConstants.LANG_Arabic, en-rIn=CommonConstants.LANG_ENGLISH_INDIA}

也就是說Map<String, String> languageChangesMap注入了<util:constant>變數。如果把application-context中的那一串<util:constant>宣告給刪掉,則會報錯:

嚴重: Caught exception while allowing TestExecutionListener [org.springframewor[email protected]5c51ee0a] to prepare test instance [[email protected]]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'me.arganzheng.study.spring.autowired.AutowiredTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Map me.arganzheng.study.spring.autowired.AutowiredTest.languageChangesMap; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    ...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 28 more

debug了一下,發現確實是Spring的一個bug。在DefaultListableBeanFactory的這個方法出問題了:

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
        ...     

        else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> keyType = descriptor.getMapKeyType();
            if (keyType == null || !String.class.isAssignableFrom(keyType)) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
                            "] must be assignable to [java.lang.String]");
                }
                return null;
            }
            Class<?> valueType = descriptor.getMapValueType();
            if (valueType == null) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
                }
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            return matchingBeans;
        }
        ...
    }

關鍵在這一句:Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);。這裡居然是用valueType作為型別去查詢bean了,當然拿到所有為String型別的bean了。

這是autowired by type的問題,但是更讓人詭異的是如果通過@Qualifier("languageChangesMap")顯式指定autowired by name,還是報錯了:

嚴重: Caught exception while allowing TestExecutionListener [org.springframewor[email protected]9476189] to prepare test instance [[email protected]]
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=languageChangesMap)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 28 more 

debug了一下,發現跟沒有指定qualifie name是一樣的執行路徑。不是指定了bean name了嗎?為什麼還是autowired by type呢?仔細查看了一下才發現。DefaultListableBeanFactory的doResolveDependency方法對首先對型別做了區別:

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return (descriptor.getField() != null ?
                    converter.convertIfNecessary(value, type, descriptor.getField()) :
                    converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
        }

        if (type.isArray()) {
            Class<?> componentType = type.getComponentType();
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return converter.convertIfNecessary(matchingBeans.values(), type);
        }
        else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> elementType = descriptor.getCollectionType();
            if (elementType == null) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
                }
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return converter.convertIfNecessary(matchingBeans.values(), type);
        }
        else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> keyType = descriptor.getMapKeyType();
            if (keyType == null || !String.class.isAssignableFrom(keyType)) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
                            "] must be assignable to [java.lang.String]");
                }
                return null;
            }
            Class<?> valueType = descriptor.getMapValueType();
            if (valueType == null) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
                }
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            return matchingBeans;
        }
        else {
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(type, "", descriptor);
                }
                return null;
            }
            if (matchingBeans.size() > 1) {
                String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
                if (primaryBeanName == null) {
                    throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
                }
                if (autowiredBeanNames != null) {
                    autowiredBeanNames.add(primaryBeanName);
                }
                return matchingBeans.get(primaryBeanName);
            }
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(entry.getKey());
            }
            return entry.getValue();
        }
    }

如果是Array,Collection或者Map,則根據集合類中元素的型別來進行autowired by type(Map使用value的型別)。為什麼這麼特殊處理呢?原來,Spring是為了達到這樣的目的:讓你可以一次注入所有符合型別的實現,也就是說可以這樣子注入:

@Autowired
private List<Car> cars;

如果你的car有多個實現,那麼都會注入進來,不會再報

org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No unique bean of type [me.arganzheng.study.spring.autowired.Car] is defined: 
expected single matching bean but found 2: [audi, toyota].

然而,上面的情況如果你用@Resource則不會有這個問題:

public class AutowiredTest extends BaseSpringTestCase {

    @Resource
    @Qualifier("languageChangesMap")
    private Map<String, String> languageChangesMap;

    @Test
    public void testAutowired() {
        assertNotNull(languageChangesMap);
        System.out.println(languageChangesMap.getClass().getSimpleName());
        System.out.println(languageChangesMap);
    }
}

正常執行:

LinkedHashMap
{pt=pt, br=pt, jp=ja, ja=ja, ind=ind, id=ind, en-rin=en-rIn, in=en-rIn, en=en, gb=en, th=th, ar=ar, eg=ar}

當然,你如果不指定@Qualifier("languageChangesMap"),同時field name不是languageChangesMap,那麼還是一樣報錯的。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER, lookup=)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 26 more

而且,@Resource也可以實現上面的List接收所有實現:

public class AutowiredTest extends BaseSpringTestCase {

    @Resource
    @Qualifier("languageChangesMap")
    private Map<String, String> languageChangesMap;

    @Resource
    private List<Car> cars;

    @Test
    public void testAutowired() {
        assertNotNull(languageChangesMap);
        System.out.println(languageChangesMap.getClass().getSimpleName());
        System.out.println(languageChangesMap);

        assertNotNull(cars);
        System.out.println(cars.getClass().getSimpleName());
        System.out.println(cars);
    }
}

執行的妥妥的:

LinkedHashMap
{pt=pt, br=pt, jp=ja, ja=ja, ind=ind, id=ind, en-rin=en-rIn, in=en-rIn, en=en, gb=en, th=th, ar=ar, eg=ar}
ArrayList
[[email protected], [email protected]]

這是因為@Resource註解使用的是CommonAnnotationBeanPostProcessor處理器,跟AutowiredAnnotationBeanPostProcessor不是同一個作者[/偷笑]。這裡就不分析了,感興趣的同學可以自己看程式碼研究一下。

最終結論如下:

@Autowired和@Inject

  • autowired by type
  • 可以 通過@Qualifier 顯式指定 autowired by qualifier name(非集合類。注意:不是autowired by bean name!)
  • 如果 autowired by type 失敗(找不到或者找到多個實現),則退化為autowired by field name(非集合類)

@Resource

  • 預設 autowired by field name
  • 如果 autowired by field name失敗,會退化為 autowired by type
  • 可以 通過@Qualifier 顯式指定 autowired by qualifier name
  • 如果 autowired by qualifier name失敗,會退化為 autowired by field name。但是這時候如果 autowired by field name失敗,就不會再退化為autowired by type了。

測試工程儲存在GitHub上,是標準的maven工程,感興趣的同學可以clone到本地執行測試一下。

補充

有同事指出Spring官方文件上有這麼一句話跟我的結有點衝突:

However, although you can use this convention to refer to specific beans by name, @Autowired is fundamentally about type-driven injection with optional semantic qualifiers. This means that qualifier values, even with the bean name fallback, always have narrowing semantics within the set of type matches; they do not semantically express a reference to a unique bean id.

也就是說@Autowired即使加了@Qualifier註解,其實也是autowired by type。@Qualifier只是一個限定詞,過濾條件而已。重新跟進了一下程式碼,發現確實是這樣子的。Spring設計的這個 @Qualifier name 並不等同於 bean name。他有點類似於一個tag。不過如果這個tag是唯一的化,那麼其實效果上等同於bean name。實現上,Spring是先getByType,得到list candicates,然後再根據qualifier name進行過濾。

再定義一個蘭博基尼,這裡使用@Qualifier指定:

package me.arganzheng.study.spring.autowired;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("luxury")
public class Lamborghini implements Car {

}

再定義一個勞斯萊斯,這裡故意用@Named指定:

package me.arganzheng.study.spring.autowired;

import javax.inject.Named;

import org.springframework.stereotype.Component;

@Component
@Named("luxury")
public class RollsRoyce implements Car {

}

測試一下注入定義的豪華車:

package me.arganzheng.study.spring.autowired;

import static junit.framework.Assert.assertNotNull;

import java.util.List;

import me.arganzheng.study.BaseSpringTestCase;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * 
 * @author zhengzhibin
 * 
 */
public class AutowiredTest extends BaseSpringTestCase {

    @Autowired
    @Qualifier("luxury")
    private List<Car> luxuryCars;

    @Test
    public void testAutowired() {

        assertNotNull(luxuryCars);
        System.out.println(luxuryCars.getClass().getSimpleName());
        System.out.println(luxuryCars);
    }

}

執行結果如下:

ArrayList
[[email protected], [email protected]]

參考文章


相關推薦

Spring各種依賴注入註解區別

Spring對於Bean的依賴注入,支援多種註解方式: @Resource javax.annotationJSR250 (Common Annotations for Java)@Inject javax.injectJSR330 (Dependency Inje

Java Spring各種依賴注入註解區別

@Resource javax.annotation JSR250 (Common Annotations for Java) @Inject javax.inject JSR330 (Dependency Injection for Java) @Autowired org.springframewo

spring依賴注入 -------基於註解方式

前言: 做了2年的軟體,剛開始入行的時候,沒有個目標基本上都是在摸索,技術看的我眼花繚亂,這個想學,那個也想學結果是對很多技術一知半解的,工作中才發現,我們要掌握的一門可以搞定快速開發搞定所有業務需求的技術, 所以現在我要對spring的東西達到一個深層次的掌握,儘量避免百度,在開發

spring依賴注入: 註解注入

註解注入顧名思義就是通過註解來實現注入, Spring和注入相關的常見註解有Autowired、Resource、Qualifier、Service、Controller、Repository、Component。 [email protected]是自動注入

Spring依賴注入註解方式)、泛型依賴注入

註解方式實現依賴注入支援手工裝配和自動裝配(慎用) 一般是宣告bean和bean直接的依賴關係的時候用比較好 使用註解方式時,也支援給Field注入值(在XML中不可以給Field注入)。另外就是setter方式注入。 @Resource註解在spring安裝目錄的lib\

spring依賴注入與控制反轉的區別

 IoC——Inversion of Control  控制反轉  DI——Dependency Injection   依賴注入         要想理解上面兩個概念,就必須搞清楚如下的問題: 參與者都有誰?依賴:誰依賴於誰?為什麼需要依賴? 注入:誰注入於誰?到底

通過自定義註解和java反射實現Spring-DI依賴注入

依賴注入的原理就是簡單說就是從頭往下遞迴生成依賴物件的,然後對引用欄位賦值最後返回。 這裡實現通過變數型別來生成相應的物件。 模擬一個使用者的註冊業務,首先是controller層呼叫service層,然後呼叫dao層程式碼實現儲存使用者。 檔案結構: UserC

Spring各種依賴注入的程式碼實現

DI:Spring稱之為依賴注入,就是維護物件和物件之間的關係 通俗的講,就是 給類的成員賦值。 1、屬性賦值: class A{ String str = “Hello Word !” } 注入: <bean id="A" class="類A

Spring依賴注入的幾種方式實現鬆耦合

一、普通注入方式: (1)在IDEA工作空間內先建立lib包然後匯入Spring的架包(複製進去的架包要按住滑鼠右鍵出現Add as Library)。 (2)在已經建立好架包的基礎上在src目錄下建立XML檔案,檔案命為applicationContext.xml,需要注意的是我們建

Spring IOC 依賴注入( 二 )

目錄 1、什麼是IOC 2、什麼是DI 3、第一個IOC示例程式 -- 通過id獲取物件(重點) 1、建立一個Java工程:             

spring 04-Spring框架依賴注入基本使用

Spring的依賴注入形式實際上所有物件產生控制都要通過applicationContext.xml檔案實現 依賴注入必須啟動容器後才可以進行該配置檔案的內部的載入操作 依賴注入之有參構造 定義一個Dept類 package cn.liang.vo; import

spring依賴注入方式總結

文章來源於今日頭條使用者:分散式系統架構 一、註解注入 註解注入在Spring中是用的最多的一種方式,就是在java程式碼中使用註解的方式進行裝配,在程式碼中加入@Resource或者@Autowired、 1、Autowired是自動注入,自動從spring的上下文找到合適的bean來

SSM(一):spring-ioc依賴注入筆記

一、java代理模式   java代理模式是ioc的前置知識。代理模式非常簡單,看程式碼就一目瞭然了。 public interface role { public void makeMoney(); } role public cla

Spring IOC 依賴注入( 二 )

目錄 圖解: 流程圖解: 圖解流程: 1、什麼是IOC IOC 全稱指的是 Inverse Of Control 控制反轉。 原

也談Spring依賴注入DI/控制反轉IOC

首先提問, 什麼是 Spring IOC 容器?         Spring 框架的核心是 Spring 容器。容器建立物件,將它們裝配在一起,配置它們並管理它們的完整生命週期。Spring 容器使用依賴注入來管理組成應用程式的元件。容器通過讀取提供的配置元資料來接收物件

通俗易懂的spring依賴注入(和控制反轉)的講解。

Spring 能有效地組織J2EE應用各層的物件。不管是控制層的Action物件,還是業務層的Service物件,還是持久層的DAO物件,都可在Spring的管理下有機地協調、執行。Spring將各層的物件以鬆耦合的方式組織在一起,Action物件無須關心Service物件的具體實現,Service

Spring依賴注入應用代替工廠模式

介面 package FactoryExample; public interface Human { void eat(); void walk(); void show(); } 實現 實現一 package FactoryExample; public clas

04 Spring框架 依賴注入(一)

整理了一下之前學習spring框架時候的一點筆記。如有錯誤歡迎指正,不喜勿噴。 上一節我們講了幾個bean的一些屬性,用來限制我們例項建立過後的狀態。 但是細心的我們會發現其實上面demo建立的例項並不完整,物件創建出來過後只有一個方法,而沒有包含其他資訊(

spring依賴注入

依賴注入的英文名Dependency Injection。與ioc差不多,不過是從兩個角度描述同一個概念。舉個栗子,一個物件A需要使用物件B來完成某個功能,可以說A依賴B,spring會在建立A時自

Spring學習,依賴注入(DI)、控制反轉(IoC)和麵向切面(AOP)

依賴注入(DI)和控制反轉(IoC) 在日常編碼中經常遇到在一個類中呼叫另一個類的多個方法,所以就在一個類中new出需要用到的類,也就是組合模式。比如說A類裡面需要用到很多B類裡面的方法,所以要在A類裡面new一個B。 public class