今天主要簡單的跟大家介紹一下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的實現原理
更多優質文章請關注以下公衆號查閱: