天天看點

Spring源碼系列 - 證明 @Autowired 不是自動裝配

證明 @Autowired 不是自動裝配

記得上一篇部落格 Spring源碼系列 - 依賴注入(Dependency Injection),我有說 @Autowired 不屬于自動裝配的範疇,隻屬于手動裝配,有同學表示不可了解,毀三觀,再此我會用代碼來證明,Talk is cheap, show me the code

上代碼前,我們先看一段 Spring 官方給除的 bean 定義:

Spring源碼系列 - 證明 @Autowired 不是自動裝配

Autowiring mode:表示 自動裝配的模型,用一個整形變量來表示

0:表示 no(不裝配)

1:表示 byName(按名稱裝配)

2:表示 byType(按類型裝配)

3:表示 constructor(根據構造函數裝配)

Spring源碼系列 - 證明 @Autowired 不是自動裝配

那現在我們就知道了,每一個 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());
    }
}
           

運作結果如下:

Spring源碼系列 - 證明 @Autowired 不是自動裝配

我們可以看出來 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);
    }
}
           

運作結果如下:

Spring源碼系列 - 證明 @Autowired 不是自動裝配

我們可以清晰的看出 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;
    }
}
           

運作結果如下:

Spring源碼系列 - 證明 @Autowired 不是自動裝配

OK,在此我們就實作了 Autowired 按類型自動注入

是以我們再次總結一下本文觀點:
  • Autowired 是手動裝配(預設)
  • xml 的自動裝配是基于 setter 和 constructor 的
  • 基于注解的自動裝配是基于 bean.setAutowireMode 的
    • 如果要實作基于注解的自動裝配,需要實作一個後置處理器,且提供setter方法