證明 @Autowired 不是自動裝配
記得上一篇部落格 Spring源碼系列 - 依賴注入(Dependency Injection),我有說 @Autowired 不屬于自動裝配的範疇,隻屬于手動裝配,有同學表示不可了解,毀三觀,再此我會用代碼來證明,Talk is cheap, show me the code
上代碼前,我們先看一段 Spring 官方給除的 bean 定義:
Autowiring mode:表示 自動裝配的模型,用一個整形變量來表示
0:表示 no(不裝配)
1:表示 byName(按名稱裝配)
2:表示 byType(按類型裝配)
3:表示 constructor(根據構造函數裝配)
那現在我們就知道了,每一個 Spring Bean 都有一個 Autowiring 字段,用來表示該 Bean 的裝配模式
現在我們先來看代碼,下面這段代碼先注釋掉了 @Autowired 注解,我們先看看這個 Bean 的裝配模式是什麼?
@Component
public class IndexService {
// @Autowired
UserService userService;
public IndexService() {
System.out.println("Constructor from IndexService");
}
@PostConstruct
public void init() {
System.out.println("userService = " + userService);
}
}
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("indexService");
System.out.println("AutowireMode = " + beanDefinition.getAutowireMode());
}
}
運作結果如下:
我們可以看出來 Bean 的定義中,AutowireMode = 0,表示沒有任何裝配,而且 userService = null
現在我們将 @Autowired 的注解去掉,繼續執行,如果 AutowireMode != 0,表示采用了其他裝配模式,我們來驗證一下
@Component
public class IndexService {
@Autowired
UserService userService;
public IndexService() {
System.out.println("Constructor from IndexService");
}
@PostConstruct
public void init() {
System.out.println("userService = " + userService);
}
}
運作結果如下:
我們可以清晰的看出 AutowireMode = 0,依然沒有用任何裝配模型,是以我們可以總結如下:
- @Autowired 屬于手動裝配,具體可以參考Spring源碼系列 - 依賴注入(Dependency Injection)
- 自動裝配僅僅在 XML 模式下存在,注解模式下,并不存在自動裝配一說
- 那麼真的是這樣麼?精彩的在下面
我們思考一下,我們可以拿到 Bean 中的 AutowireMode 值,那麼我們是否可以改變這個值呢?如果改變了整個值,那麼是不是就實作了 @Autowired 自動裝配呢?
繼續試驗…
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("indexService");
// 這裡我們設定了 AutowireMode 為 AUTOWIRE_BY_TYPE,也就是按類型注入
beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
System.out.println("AutowireMode = " + beanDefinition.getAutowireMode());
}
}
同時我們再次注釋掉了 @Autowired 注解,增加了 setUserService 方法,因為我們知道無論是按名稱還是按類型注入,都是利用 setter 方式來實作的
@Component
public class IndexService {
// @Autowired
UserService userService;
public IndexService() {
System.out.println("Constructor from IndexService");
}
@PostConstruct
public void init() {
System.out.println("userService = " + userService);
}
// 增加了 setter 方法
public void setUserService(UserService userService) {
this.userService = userService;
}
}
運作結果如下:
OK,在此我們就實作了 Autowired 按類型自動注入
是以我們再次總結一下本文觀點:
- Autowired 是手動裝配(預設)
- xml 的自動裝配是基于 setter 和 constructor 的
- 基于注解的自動裝配是基于 bean.setAutowireMode 的
- 如果要實作基于注解的自動裝配,需要實作一個後置處理器,且提供setter方法