三分鐘學會@Autowired@Qualifier@Primary註解

今天主要簡單的跟大家介紹一下spring自動裝配相關的@Autowired,@Qualifier和@Primary註解


1,@Autowired註解的使用


繼續上文深入理解spring註解之@ComponentScan註解中的例子,現在我們需要在UserService中調用UserDao相關操作,那我們可以在UserService中增加如下代碼:


import com.zhang.dao.UserDao;
@Service
public class UserService {
   @Autowired
   private UserDao userDao;
   /**
    * 增加一個tostring方法 方便測試
    */

   @Override
   public String toString() {
       return "UserService [userDao=" + userDao + "]";
   }
}


測試代碼如下:


AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainScanConfig.class);
UserService object = (UserService) applicationContext2.getBean("userService");
System.out.println("實例bean爲 === "+object);


運行結果如下:


實例bean爲 === UserService [userDao=com.zhang.dao.UserDao@51b279c9]


根據運行結果我們可以發現userDao已經成功注入到UserService中了


假設現在業務中有一種情況是UserDao是第三方提供的服務,我們也不能保證其是否可以成功加入到spring容器中,那我們也不能因爲UserDao沒能成功注入到spring容器而使我們整個UserService服務都不能使用,那這邊我們就來演示一下這種情況,如下我們註釋掉UserDao的@Repository註解:


import org.springframework.stereotype.Repository;
//@Repository
public class UserDao {
}


這個時候你再啓動測試類會報如下錯誤:


警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zhang.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zhang.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
   at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
   at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
   at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1268)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
   at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
   at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
   at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
   at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
   at com.zhang.ApplicationTest.main(ApplicationTest.java:31)


其實很簡單這個時候我們只需要在@Autowired註解中加上如下屬性:


@Autowired(required=false)
private UserDao userDao;


再次運行測試類你會發現錯誤已經消失只是這個時候userDao是null如下:


實例bean爲 === UserService [userDao=null]


2,@Qualifier註解的使用


把UserDao代碼修改爲如下:


import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
   // 給一個默認值
   private Integer version = 0;
   /**
    * 增加tostring方便測試
    */

   @Override
   public String toString() {
       return "UserDao [version=" + version + "]";
   }
   /**
    * @return the version
    */

   public Integer getVersion() {
       return version;
   }
   /**
    * @param version the version to set
    */

   public void setVersion(Integer version) {
       this.version = version;
   }
}


同時在配置類中增加一個@Bean的UserDao配置如下:


@Bean(value = "userDao2")
public UserDao getUserDao(){
       UserDao userDao = new UserDao();
       userDao.setVersion(2);
       return userDao;
}


運行測試類結果如下:


實例bean爲 === UserService [userDao=UserDao [version=0]]


我們可以發現這個時候用的是默認的掃描到的UserDao,這個時候我們把UserService中注入的UserDao改成如下:


@Autowired(required=false)
private UserDao userDao2;


繼續運行測試類結果如下:


實例bean爲 === UserService [userDao=UserDao [version=2]]


從以上運行結果我們可以發現如果有多個同類型的bean默認是根據對應的bean名稱注入的,那如果這個時候我們不想使用spring默認的注入方式而是希望根據自己業務需要指定固定的bean,那就是@Qualifier註解表現的時候瞭如下:


@Qualifier(value="userDao")
@Autowired(required=false)
private UserDao userDao2;


這個時候不管你UserDao定義什麼名字永遠只會注入userDao這個bean了


3,@Primary註解的使用


不管是因爲潔癖還是什麼也好可能有些同學不是特別喜歡使用@Qualifier註解,那麼沒關係,spring還爲我們提供了另外一個註解@Primary同樣可以實現以上功能


假設現在我們UserService中注入的UserDao是userDao2,這麼這個時候我們可以在配置類中的UserDao上增加@Primary註解如下:


@Primary
@Bean(value = "userDao2")
public UserDao getUserDao(){
       UserDao userDao = new UserDao();
       userDao.setVersion(2);
       return userDao;
}


這個時候運行測試類你會發現UserService注入的就是userDao2了


注意:這個時候UserService中的UserDao就不能再加@Qualifier對應的註解了


以上是今天文章的所有內容,歡迎大家吐槽


推薦閱讀


深入理解spring生命週期與BeanPostProcessor的實現原理

250G偷懶必看資料全集


更多優質文章請關注以下公衆號查閱:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章