1. 程式人生 > >Spring註解@Autowired、@Resource、@Inject

Spring註解@Autowired、@Resource、@Inject

Spring注入的方式有很多,下面介紹一下常用的幾個用於注入的註解

@Autowired

首先來看一下@Autowired註解的定義:

@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註解只有一個required屬性,預設為true,說明預設情況下是要求一定要有物件注入才行,要不然會報空指標異常。如果允許為null,可以設定required為false。

下面我們來通過一個例子看一下@Autowired在不同地方的注入:

public class Cat {

  public String show(){
    return "Cat";
  }

}

public
class Dog { public String show(){ return "Dog"; } } public class Cattle { public String show(){ return "Cattle"; } }

@Configuration
public class ServiceConfig {

  @Autowired
  private Dog dog;
  private Cat cat;
  private Cattle cattle;

  @Autowired
  public ServiceConfig(Cattle cattle){
    this
.cattle = cattle; } @Autowired public void setCat(Cat cat){ this.cat = cat; } public String getDesc(){ return dog.show() + "|" + cat.show() + "|" + cattle.show(); } }
public class ServiceDemoMain {
  public static void main(String[] args){
    AnnotationConfigApplicationContext  context = new AnnotationConfigApplicationContext();
    context.register(Config.class, ServiceConfig.class);
    context.refresh();

    ServiceConfig config = context.getBean(ServiceConfig.class);
    System.out.println(config.getDesc());
  }
}

@Autowired註解預設是通過型別來注入的,假如同一個型別的物件存在多個,就會出現物件的歧義,Spring不知道該注入哪個物件了,如下:

@Service
public class UserServiceImpl implements UserService {

}

@Service
public class UserServiceImpl2 implements UserService {

}

public class Test{
   @Autowired
   private UserService userService;
}

如何解決多個物件的歧義性呢? 1.通過名稱注入,配置Qualifier註解通過名稱來注入,通過給不同的物件設定不同的名稱來實現注入

@Service("UserServiceImpl")
public class UserServiceImpl implements UserService {

}

@Service("UserServiceImpl2")
public class UserServiceImpl2 implements UserService {

}

public class Test{
   @Autowired
   @Qualifier("UserServiceImpl")
   private UserService userService;
}

2.使用@Primary註解來標識,假如有同一個型別的多個物件存在,會優先注入@Primary標記的物件。注意:同一個型別的物件,只能有一個用@Primary來標記,如果多個物件都標識了@Primary,還是會存在歧義的問題

@Service
public class UserServiceImpl implements UserService {

}

@Service
@Primary
public class UserServiceImpl2 implements UserService {

}

public class Test{
   @Autowired
   private UserService userService;
}

@Resource

  • @Resource預設是通過name來注入的,有兩個重要屬性可以指定:name和type
  • 預設情況下,既不指定name,也不指定type,會預設按照name來查詢匹配的物件,當有唯一的物件則進行注入;若沒有,則嘗試用type來進行匹配,匹配到唯一物件,則進行注入
  • 指定name屬性,則用name來進行查詢,沒有則直接拋異常
  • 指定type屬性,則用type來進行匹配,沒有則直接拋異常
@Configuration
public class Config {
@Bean(name="userServiceImpl")
  public UserService getUserServiceImpl(){
    return new UserServiceImpl();
  }

  @Bean(name="userServiceImpl2")
  public UserService getUserServiceImpl2(){
    return new UserServiceImpl2();
  }
}  

/**
* 預設通過名稱來注入
**/
@Resource
private UserService userServiceImpl;
@Resource
private UserService userServiceImpl2;

當名稱沒有匹配時,則用型別來進行匹配

@Configuration
public class Config {
@Bean(name="userServiceImpl")
  public UserService getUserServiceImpl(){
    return new UserServiceImpl();
  }
}

/**
* userServiceImpl2通過名稱沒有匹配上時,則用型別進行匹配,兩個物件都注入userServiceImpl
**/
@Resource
private UserService userServiceImpl;
@Resource
private UserService userServiceImpl2;

@Inject

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

從原始碼可以看出@Inject可以用在普通方法、構造方法、欄位上,@Inject沒有required屬性,物件為空會拋異常

  • @Inject是JSR330 (Dependency Injection for Java)中的規範,需要匯入javax.inject.Inject
  • @Inject與@Autowired一樣,預設是按照型別來實現注入的,型別注入沒有找到則用名稱去匹配,只是@Autowired是Spring提供的,@Inject是J2EE提供的
  • @Inject通過型別匹配到多個物件時,跟@Autowired一樣會產生歧義,不知道該注入哪一個物件,當出現歧義時配合@Named註解按名稱來進行注入
  @Inject
  @Named("userServiceImpl")
  private UserService userService;


  @Bean(name="userServiceImpl")
  public UserService getUserServiceImpl(){
    return new UserServiceImpl();
  }

  @Bean(name="userServiceImpl2")
  public UserService getUserServiceImpl2(){
    return new UserServiceImpl2();
  }

@Inject通過型別注入沒有找到唯一的物件後,還會通過名稱匹配,匹配上也是可以成功注入的

  /**
  * 測試發現,這樣也可以注入成功,說明@Inject不光通過型別來注入,也會通過屬性名userServiceImpl2來進行注入
  **/
  @Inject
  private UserService userServiceImpl2;


 @Bean(name="userServiceImpl")
  public UserService getUserServiceImpl(){
    return new UserServiceImpl();
  }

  @Bean(name="userServiceImpl2")
  public UserService getUserServiceImpl2(){
    return new UserServiceImpl2();
  }

@Autowired、@Resource、@Inject三者間的區別

(1)、@Autowired預設是按照型別裝配注入的,型別沒有注入成功,會用物件名稱來進行注入,預設情況下它要求依賴物件必須存在如果允許為null,可以設定它required屬性為false,如果想按照自定義名稱來進行注入,則需要結合@Qualifier一起使用;@Inject與@Autowired一樣,只是@Inject沒有required屬性,@Inject想按照自定義名稱來進行注入需結合@Named註解使用,當然結合@Qualifier也可以

(2)、@Resource預設按照名稱裝配,當找不到與名稱匹配的bean才會按照型別裝配,可以通過name屬性指定,如果沒有指定name屬 性,當註解標註在欄位上,即預設取欄位的名稱作為bean名稱尋找依賴物件,當註解標註在屬性的setter方法上,即預設取屬性名作為bean名稱尋找 依賴物件.注意:如果沒有指定name屬性,並且按照預設的名稱仍然找不到依賴的物件時候,會按照型別裝配,但一旦指定了name屬性,就只能按照名稱裝配了.

(3)、@Resource、@Inject註解是由J2EE提供,@Resource是JSR-250提供的註解,@Inject是JSR-330提供的註解,而@Autowired是由spring提供;

(4)、@Resource、@Autowired、@Inject都可以書寫標註在欄位或者該欄位的setter方法之上