@Autowired、@Resource和@Inject註解的區別(最詳細)

     在Spring中依賴注入可以使用@Autowired、@Resource和@Inject來完成,並且在一般的使用中是可以相互替換的(注意是一般),不過三者還是有區別,今天來介紹一下他們的區別:

     @Autowired註解:

        1.Spring本身替換的註解(org.springframework.beans.factory.annotation.Autowired),需要導入Spring相應的jar包才能使用

        2.可以標註的位置:構造器、方法、方法參數、變量域和註解上面

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

       3.在Spring容器解析@Autowired註解時,使用的後置處理器爲AutowiredAnnotationBeanPostProcessor,在這個後置處理的註釋中有這麼一段:

{@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
* implementation that autowires annotated fields, setter methods, and arbitrary
* config methods. Such members to be injected are detected through annotations:
* by default, Spring's {@link Autowired @Autowired} and {@link Value @Value}
* annotations.
*
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
* if available, as a direct alternative to Spring's own {@code @Autowired}.

        4. @Autowired註解有一個required屬性,當指定required屬性爲false時,意味着在容器中找相應類型的bean,如果找不到則忽略,而不報錯(這一條是兩個註解所沒有的功能)。

       5. 默認優先按照類型去容器中找對應的組件,找到就賦值,如果找到多個相同類型的組件,再將屬性的名稱作爲組件的id去容器中查找,如果組件id對象的bean不存在,而且required屬性爲true,就報錯。

       6. 支持@Primary註解,讓Spring進行自動裝配的時候,默認使用首選的bean;

      @Resource

         1.JSR250規範提供的註解(javax.annotation.Resource),不需要導入格外的包,這個註解在JDK的rt.jar包中

         2.可以標註的位置:TYPE(表示可以標註在接口、類、枚舉),FIELD(變量域)和METHOD(方法)上面。

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    String name() default "";

    String lookup() default "";

    Class<?> type() default java.lang.Object.class;

    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }

    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;

    boolean shareable() default true;

    String mappedName() default "";

    String description() default "";
}

      3.在Spring容器解析@Resource註解時,使用的後置處理器爲CommonAnnotationBeanPostProcessor,在這個後置處理的註釋中有這麼一段: 

* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
* that supports common Java annotations out of the box, in particular the JSR-250
* annotations in the {@code javax.annotation} package. These common Java
* annotations are supported in many Java EE 5 technologies (e.g. JSF 1.2),
* as well as in Java 6's JAX-WS.
*
* <p>This post-processor includes support for the {@link javax.annotation.PostConstruct}
* and {@link javax.annotation.PreDestroy} annotations - as init annotation
* and destroy annotation, respectively - through inheriting from
* {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.
*
* <p>The central element is the {@link javax.annotation.Resource} annotation
* for annotation-driven injection of named beans, by default from the containing
* Spring BeanFactory, with only {@code mappedName} references resolved in JNDI.
* The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups
* equivalent to standard Java EE 5 resource injection for {@code name} references
* and default names as well. The target beans can be simple POJOs, with no special
* requirements other than the type having to match.

      4. 默認是按照組件名稱進行裝配的

      5. 支持@Primary註解,不過首先按照會按照名稱進行注入bean,如果Spring IOC容器中沒有該Bean,則按照@Primary註解標註的bean進行裝配(這條是我自己總結的,別人都說不支持,但是代碼是不會騙人的,給出驗證代碼,如有錯誤,請多指教,這個代碼的邏輯其實可以看一下CommonAnnotationBeanPostProcessor是怎麼處理的,有時間我來看看源碼

     下面驗證@Resource默認是按照組件名稱進行裝配的和持支@Primary註解的:

@Configuration
@ComponentScan({"it.cast.resouce"})
public class ResourceConfig {

    @Primary   //標有Primary註解,使用@Autowired@Inject註解註解時,優先被加載
    @Bean
    public Y y1(){
        Y y = new Y();
        y.setI(0);
        return y;
    }

}

@Component
public class X {
    @Resource   //這裏使用的是@Resource註解,該註解默認按照組件名稱進行裝配的,所以會優先加載id爲y的bean
    private Y y;

    public Y getY() {
        return y;
    }

    public void setY(Y y) {
        this.y = y;
    }
}

@Component
public class Y {
    private int i = 2;

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}

      測試一下使用,使用@Resource註解的打印結果:

    @Test
    public void ResourceConfigTest(){
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ResourceConfig.class);

        X bean = context.getBean(X.class);
        System.out.println(bean.getY().getI());
    }
    //輸出結果爲:
    //     2
    //從而驗證了@Resource默認按照名稱進行加載

     此時,將@Resource註解的屬性名稱換成y12,這個bean在容器裏面沒有的

@Configuration
@ComponentScan({"it.cast.resouce"})
public class ResourceConfig {

    @Primary   //標有Primary註解,使用@Autowired@Inject註解註解時,優先被加載
    @Bean
    public Y y1(){
        Y y = new Y();
        y.setI(0);
        return y;
    }

}

@Component
public class X {
    @Resource       //這裏使用的是@Resource註解,該註解默認按照組件名稱進行裝配的,所以會優先加載id爲y12的bean,
    private Y y12;  //如果找不到則按Primary註解標註的bean進行注入

    public Y getY() {
        return y12;
    }

    public void setY(Y y) {
        this.y12 = y;
    }
}

@Component
public class Y {
    private int i = 2;

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}

      測試一下使用,使用@Resource註解的打印結果: 

    @Test
    public void ResourceConfigTest(){
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ResourceConfig.class);

        X bean = context.getBean(X.class);
        System.out.println(bean.getY().getI());
    }
    //輸出結果爲:
    //     0
    //由於沒有找到id爲y12的bean,所以注入了使用@Primary標註的bean,
    //而且整個程序沒有報錯,所以驗證了@Resource支持@Primary註解

      此時,將@Resource註解換成@Autowired註解的打印結果:

@Configuration
@ComponentScan({"it.cast.resouce"})
public class ResourceConfig {

    @Primary   //標有Primary註解,使用@Autowired@Inject註解註解時,優先被加載
    @Bean
    public Y y1(){
        Y y = new Y();
        y.setI(0);
        return y;
    }

}

@Component
public class X {
    @Autowired   
    private Y y;  //此時不管名稱是y還是y12,都會使用標有Primary註解的bean

    public Y getY() {
        return y;
    }

    public void setY(Y y) {
        this.y = y;
    }
}

@Component
public class Y {
    private int i = 2;

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}

    測試一下使用,使用@Autowired註解的打印結果: 

    @Test
    public void ResourceConfigTest(){
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ResourceConfig.class);

        X bean = context.getBean(X.class);
        System.out.println(bean.getY().getI());
    }
    //輸出結果爲:
    //     0
    //從而驗證了@Autowired支持@Primary註解

      @Inject

          1.JSR330規範提供的註解(javax.inject.Inject),主要導入javax.inject包才能使用

          2.可以標註的位置:方法、構造器和變量域中

@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Inject {}  //該註解中沒有任何屬性

         3.在Spring容器解析@Inject註解時,使用的後置處理器和@Autowired是一樣的,都是AutowiredAnnotationBeanPostProcessor。

         4.由於@Inject註解沒有屬性,在加載所需bean失敗時,會報錯

         除了上面的不同點之後,@Inject和@Autowired完全等價。

發佈了221 篇原創文章 · 獲贊 30 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章