【Spring】Autowired原理及與Resource註解區別

Autowired註解

Autowired顧名思義,表示自動注入,以下是Autowired註解的源代碼:java

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    /** * Declares whether the annotated dependency is required. * <p>Defaults to {@code true}. */
    boolean required() default true;

}
複製代碼

從Autowired的實現能夠看到,Autowired能夠用於類的構造方法,類的字段,類的方法以及註解類型上,可是Autowired不能用於類上面。app

關於Autowired註解,有以下問題須要解決:ide

1. Autowired做用在不一樣的範圍上(構造方法,字段、方法)上,它的裝配策略如何,按名稱仍是類型?ui

2. 爲構造方法,字段和方法添加Autowired註解以後,誰來解析這個Autowired註解,完成裝配this

3. 裝配的bean從何處而來,是在Spring的xml文件中定義的bean嗎?spa

從Autowired的javadoc開始

從Autowired的javadoc中獲得以下信息3d

1. AutowiredAnnotationBeanPostProcessor負責掃描Autowired註解,而後完成自動注入code

2. 能夠對私有的字段使用Autowired進行自動裝配,而無需爲私有字段定義getter/setter來read/write這個字段component

3. 使用Autowired註解的類方法,能夠是任意的方法名,任意的參數,Spring會從容器中找到合適的bean進行裝配,setter自動注入跟對字段自動注入效果同樣orm

Autowired註解的解析

當項目中使用了Autowired註解時,須要明確的告訴Spring,配置中引用了自動注入的功能,在Spring的配置文件,作法有兩種

1. 配置AutowiredAnnotationBeanPostProcessor

2. 使用context:annotation-config/context:annotationconfig/ 將隱式地向 Spring 容器註冊AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor以及equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。

實例

1. 實例一:

  • UserSerice依賴的UserDao使用Autowired註解,

  • UserDao沒有在Spring配置文件中定義

結果:UserDao爲null

2. 實例二:

  • UserSerice依賴的UserDao使用Autowired註解

  • UserDao在Spring配置文件中有定義

結果:UserDao爲null

3. 實例三:

  • UserSerice依賴的UserDao使用Autowired註解

  • UserDao在Spring配置文件中有定義

  • Spring中使用context:annotation-config/

**   結果:UserDao正確注入,在Spring中配置的UserDao的實現,而在UserService中的是UserDao的接口,也就是說,雖然它們類型沒有徹底匹配,可是因爲是實現**

關係,Spring仍然可以完成自動注入

4. 實例四:

  • UserSerice依賴的UserDao使用Autowired註解

  • UserDao在Spring配置文件中有定義

  • Spring中配置AutowiredAnnotationBeanPostProcessor

結果:UserDao正確注入,同實例三

5. 實例五:

  • UserSerice依賴的UserDao使用Autowired註解

  • UserDao在Spring配置文件中有兩份定義(id不一樣)

  • Spring中使用context:annotation-config/

結果:

1. 若是UserDao的屬性名與某個bean的id相同,那麼按照屬性名和id名稱匹配原則,自動裝配

2. 若是UserService中定義的UserDao的屬性名,與Spring配置文件中的兩個id都不一樣,那麼注入失敗,異常拋出,提示,沒法完整自動裝配

結論:

1. 使用Autowired自動裝配,必須在Spring的配置文件中使用context:annotation-config/來告訴Spring須要進行自動裝配掃描(AutowiredAnnotationBeanPostProcessor不推薦使用)

2. Autowired默認按類型進行匹配,當匹配到多個知足條件的bean時,再按照屬性名和bean的id進行匹配,若是仍然有多個匹配上或者沒有一個匹配上,則拋出異常,提示自動裝配失敗

3. 在使用Autowired時,能夠使用Qualifier註解,顯式的指定,當衝突發生時,使用那個id對應的bean

4. Autowired註解自動裝配功能完成的是依賴的自動注入,所以,在一個bean中,它依賴的bean能夠經過自動注入的方式完成而不須要顯式的爲它的屬性進行注入。可是這些依賴的bean仍然不能省略,仍是要在Spring中進行配置,省略的僅僅是bean屬性的注入配置代碼

Resource註解

Resource註解在功能和目的上,等效於Autowried+Qualifier註解,Resource註解是JSR-250規範的一部分,它定義在JDK的javax.annoation包中,以下是它的定義:

package javax.annotation;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

/** * The Resource annotation marks a resource that is needed * by the application. This annotation may be applied to an * application component class, or to fields or methods of the * component class. When the annotation is applied to a * field or method, the container will inject an instance * of the requested resource into the application component * when the component is initialized. If the annotation is * applied to the component class, the annotation declares a * resource that the application will look up at runtime. <p> * * Even though this annotation is not marked Inherited, deployment * tools are required to examine all superclasses of any component * class to discover all uses of this annotation in all superclasses. * All such annotation instances specify resources that are needed * by the application component. Note that this annotation may * appear on private fields and methods of superclasses; the container * is required to perform injection in these cases as well. * * @since Common Annotations 1.0 */
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    /** * The JNDI name of the resource. For field annotations, * the default is the field name. For method annotations, * the default is the JavaBeans property name corresponding * to the method. For class annotations, there is no default * and this must be specified. */
    String name() default "";

    /** * The name of the resource that the reference points to. It can * link to any compatible resource using the global JNDI names. * * @since Common Annotations 1.1 */

    String lookup() default "";

    /** * The Java type of the resource. For field annotations, * the default is the type of the field. For method annotations, * the default is the type of the JavaBeans property. * For class annotations, there is no default and this must be * specified. */
    Class<?> type() default java.lang.Object.class;

    /** * The two possible authentication types for a resource. */
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }

    /** * The authentication type to use for this resource. * This may be specified for resources representing a * connection factory of any supported type, and must * not be specified for resources of other types. */
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;

    /** * Indicates whether this resource can be shared between * this component and other components. * This may be specified for resources representing a * connection factory of any supported type, and must * not be specified for resources of other types. */
    boolean shareable() default true;

    /** * A product specific name that this resource should be mapped to. * The name of this resource, as defined by the <code>name</code> * element or defaulted, is a name that is local to the application * component using the resource. (It's a name in the JNDI * <code>java:comp/env</code> namespace.) Many application servers * provide a way to map these local names to names of resources * known to the application server. This mapped name is often a * <i>global</i> JNDI name, but may be a name of any form. <p> * * Application servers are not required to support any particular * form or type of mapped name, nor the ability to use mapped names. * The mapped name is product-dependent and often installation-dependent. * No use of a mapped name is portable. */
    String mappedName() default "";

    /** * Description of this resource. The description is expected * to be in the default language of the system on which the * application is deployed. The description can be presented * to the Deployer to help in choosing the correct resource. */
    String description() default "";
}

複製代碼

Autowried註解,首先根據類型匹配,若是類型匹配到多個,那麼在根據屬性名和bean的id進行匹配(能夠由Qualifier註解強制匹配指定的bean id)。Resource註解則順序不一樣,它有以下幾種可能的狀況:

  • Resource註解指定了name屬性和type屬性

策略:首先進行按名稱匹配策略: 匹配name屬性和bean的id,若是匹配,則判斷查找到的bean是不是type屬性指定的類型,若是是type屬性指定的類型,則匹配成功。若是不是type屬性指定的類型,則拋出異常,提示匹配失敗;若是name屬性跟bean的id不匹配,則拋出異常提示沒有bean的id匹配name屬性

  • Resource註解指定了name屬性,未指定type屬性

策略:查找bean的id爲name屬性的bean,查找到,不關心類型爲何,都是匹配成功;若是找不到name屬性指定的bean id,則匹配失敗,拋出異常

  • Resource註解指定了type屬性,未指定name屬性

策略:首先進行按名稱匹配策略: 匹配屬性名和bean的id,若是匹配,則判斷查找到的bean是不是type屬性指定的類型,若是是type屬性指定的類型,則匹配成功。若是不是type屬性指定的類型,則拋出異常,提示匹配失敗;其次進行按類型匹配策略: 若是屬性名跟bean的id不匹配,則查找類型爲type的bean,若是僅僅找到一個,自動裝配成功,其它狀況失敗。

  • Resource註解未指定type屬性和name屬性

策略:首先進行按屬性名匹配策略,匹配則注入成功;若是屬性名不匹配,則進行類型匹配策略,只有爲一個類型匹配才成功,其餘狀況都失敗

做者注:歡迎關注筆者公號,按期分享IT互聯網、金融等工做經驗心得、人生感悟,歡迎交流,目前就任阿里-移動事業部,須要大廠內推的也可到公衆號砸簡歷,或查看我我的資料獲取。(公號ID:weknow619)。

相關文章
相關標籤/搜索