spring自動注入的三種方式


所謂spring自動注入,是指容器中的一個組件中需要用到另一個組件(例如聚合關系)時,依靠spring容器創建對象,而不是手動創建,主要有三種方式:
1. @Autowired注解——由spring提供
2. @Resource注解——由JSR-250提供
3. @Inject注解——由JSR-330提供
 
@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;

}
從源碼可以看出:該注解可以用在構造器、方法、參數、屬性上,最常見的是用在屬性上。
該注解只有一個屬性: required,默認為true,如果找不到匹配的bean則報錯;設置為false,如果找不到匹配的bean則注入null,並不會報錯。
可以配合@Qualifier使用,用於精准指定要注入的bean的名稱。
可以配合@Primary使用,當容器中存在多個相同類型的組件時,用於指定優先加載哪一個,這個注解不能用在2個或更多同類型的組件上。
 
1. 當容器中只有一個該類型的組件時
|-不使用@Qualifier,會按bean類型查找,即applicationContext.getBean(bean.class),然后注入這個唯一的bean。
|-使用@Qualifier,會按Qualifier的value值跟bean名稱匹配查找,即applicationContext.getBean("Qualifier的value值")。
2. 當容器中沒有該類型的組件時
|-required=true——報錯expected at least 1 bean which qualifies as autowire candidate。
|-required=false——注入null。
3. 當容器中存在多個該類型的組件時
|-不使用@Qualifier和@Primary時,會按屬性名跟bean名稱匹配查找,即applicationContext.getBean("屬性名")。
|-使用@Primary、但不使用@Qualifier時,會優先加載帶有@Primary注解的組件。
|-使用@Qualifier時,不管有沒有使用@Primary,都會直接按Qualifier的value值跟bean名稱匹配查找。
綜上,當容器中存在多個同類型的組件時,加載優先級:@Qulifier>@Primary>屬性名,例如下面這個容器中包含3個BookDao組件
@Configuration
@ComponentScan(basePackages = {"cn.monolog.service"})
public class AutowiredBeanConfig {

    @Bean(value = "bookDao1")
    public BookDao bookDao1() {
        BookDao bookDao = new BookDao();
        bookDao.setLabel("bookDao1");
        return bookDao;
    }

    @Bean(value = "bookDao2")
    @Primary
    public BookDao bookDao2() {
        BookDao bookDao = new BookDao();
        bookDao.setLabel("bookDao2");
        return bookDao;
    }

    @Bean(value = "bookDao3")
    public BookDao bookDao3() {
        BookDao bookDao = new BookDao();
        bookDao.setLabel("bookDao3");
        return bookDao;
    }
}
自動注入方式是這樣的:
@Autowired
@Qualifier(value = "bookDao1")
private BookDao bookDao3;
按照優先級順序,@Qulifier(bookDao1) > @Primary(bookDao2) > 屬性名(bookDao3),最終加載的是名稱為bookDao1的組件。
 

@Resource注解的使用方法
@Resource注解的使用跟@Autowired注解類似,但是需要注意:
1. 不支持@Primary注解,也不支持reuqired=false,即不允許注入null;
2. 該注解有一個屬性name,類似於@Qualified精准匹配,優先級最高;
3. 默認按照屬性名跟bean的名稱匹配查找,如果不存在,再按類型匹配查找。
例如,下面這個容器中有兩個CarDao組件
@Configuration
@ComponentScan(basePackages = {"cn.monolog.service"})
public class ResourceBeanConfig {

    @Bean(value = "carDao1")
    public CarDao carDao1() {
        CarDao carDao = new CarDao();
        carDao.setLabel("1");
        return  carDao;
    }

    @Bean(value = "carDao2")
    public CarDao carDao() {
        CarDao carDao = new CarDao();
        carDao.setLabel("2");
        return  carDao;
    }
}
自動注入方式如下,會按屬性名注入carDao2組件。
//自動注入
@Resource
private CarDao carDao2;
但是改為下面這種注入方式:
//自動注入
@Resource(name = "carDao1")
private CarDao carDao2;
由於使用了name精准匹配,會忽略屬性名,注入carDao1組件。
 

@Inject注解的使用方法
@Inject注解的使用方法跟@Autowired也基本相似,但是需要注意
1. 使用前需要導入jar包——javax.inject;
2. 支持@Primary注解,而且因為沒有精確匹配,@Primary的優先級最高;
2. 不支持required=false,即不能注入null,如果找不到組件肯定報錯;
3. 默認按照屬性名跟bean的名稱匹配查找,如果不存在,再按類型匹配查找。
 
例如,下面這容器中有一個EmployeeDao組件
@Configuration
public class InjectBeanConfig {
    @Bean(value = "employeeDao1")
    public EmployeeDao employeeDao1() {
        EmployeeDao employeeDao = new EmployeeDao();
        employeeDao.setLabel("1");
        return employeeDao;
    }
}
自動注入的方式如下
@Inject
private EmployeeDao employeeDao3;
spring會先按屬性名查找名稱為employeDao3的組件,即applicationContext.getBean("employeeDao3"),結果不存在;
然后按照類型查找,即applicationContext.getBean(EmployeDao.class),找到employeDao1組件,成功注入。
 
如果容器中有多個同類型組件,例如
@Configuration
public class InjectBeanConfig {
    @Bean(value = "employeeDao1")
    public EmployeeDao employeeDao1() {
        EmployeeDao employeeDao = new EmployeeDao();
        employeeDao.setLabel("1");
        return employeeDao;
    }
    @Bean(value = "employeeDao2")
    public EmployeeDao employeeDao2() {
        EmployeeDao employeeDao = new EmployeeDao();
        employeeDao.setLabel("2");
        return employeeDao;
    }
    @Bean(value = "employeeDao3")
    public EmployeeDao employeeDao3() {
        EmployeeDao employeeDao = new EmployeeDao();
        employeeDao.setLabel("3");
        return employeeDao;
    }
}
注入方式還是這樣
@Inject
private EmployeeDao employeeDao3;
仍然會按屬性名和bean的名稱匹配,即applicationContext.getBean("employeeDao3"),找到employee3,成功注入。
 
但是如果其中某個組件加了@Primary注解,會忽略屬性名,優先注入,例如
@Configuration
public class InjectBeanConfig {
@Bean(value
= "employeeDao1") public EmployeeDao employeeDao1() { EmployeeDao employeeDao = new EmployeeDao(); employeeDao.setLabel("1"); return employeeDao; }
@Bean(value
= "employeeDao2") @Primary
public EmployeeDao employeeDao2() { EmployeeDao employeeDao = new EmployeeDao(); employeeDao.setLabel("2"); return employeeDao; }
@Bean(value
= "employeeDao3") public EmployeeDao employeeDao3() { EmployeeDao employeeDao = new EmployeeDao(); employeeDao.setLabel("3"); return employeeDao; } }
無論注入時使用什么樣的屬性名,都會注入employeeDao2。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM