01.16 Springboot中的javaConfig詳解(基於Spring5.2)

在Spring3.0之前,我們的bean一直通過XML文件來配置的,後來在Spring3.0之後為我們提供了java的config版本。而且在Spring4.0之後推薦我們使用,這篇文章基於Spring5.2來分析。希望在平時使用和麵試的時候對你有一絲幫助。

一、實例演示

我們先給出一個例子,看看如何使用,然後再來分析。創建一個普通的maven項目。

第一步:添加pom依賴

Springboot中的javaConfig詳解(基於Spring5.2)

這裡面添加了最核心的依賴。

第二步:在bean包添加User類

Springboot中的javaConfig詳解(基於Spring5.2)

第三步:在service包添加UserService類

Springboot中的javaConfig詳解(基於Spring5.2)

注意這裡沒有@Service註解。目的就是我們自己注入。

第四步:在config包添加UserConfig類

Springboot中的javaConfig詳解(基於Spring5.2)

這個類是核心,我們使用了倆註解,一個Configuration還有一個Bean。我們一會就看他倆的作用。

第五步:測試

之前我們已經添加了測試依賴。直接測試一波:

Springboot中的javaConfig詳解(基於Spring5.2)

這就是一個最基本的案例,實現起來非常的簡單。下面我們著重分析一下這倆註解的作用,為什麼能實現類似於Spring中XML文件一樣的作用。

二、分析

1、註解角度分析

想要了解為什麼@Configuration會有這樣的作用,我們可以跟進去這個註解看看。

Springboot中的javaConfig詳解(基於Spring5.2)

進去之後我們會發現,這個註解標籤是一個元註解,由很多其他的註解實現,有一個我們應該很熟悉,那就是@Component,有著了這個註解就可以被@ComponentScan掃描並處理。Spring5.0已經自動掃描了,不需要我們自己再去添加了。現在我們進去到裡面的代碼看看:

首先是@AliasFor標籤:

在Spring的眾多註解中,經常會發現很多註解的不同屬性起著相同的作用,比如@RequestMapping的value屬性和path屬性,這就需要做一些基本的限制,比如value和path的值不能衝突,比如任意設置value或者設置path屬性的值,都能夠通過另一個屬性來獲取值等等。為了統一處理這些情況,Spring創建了@AliasFor標籤。

然後是value() :

意思是默認的值就是空,此時我們就可以指定@Configuration(value="屬性值")的這種方式,因為只有一個value所以value可以省去不寫。

最後是proxyBeanMethods:

有了 proxyBeanMethods 屬性後,配置類不會被代理了。主要是為了提高性能,如果你的 @Bean 方法之間沒有調用關係的話可以把 proxyBeanMethods 設置為 false。否則,方法內部引用的類生產的類和 Spring 容器中類是兩個類。

3、運行角度分析

現在我們把目光轉移,從測試運行的角度來分析。

Springboot中的javaConfig詳解(基於Spring5.2)

看到這裡,可能就要深入到Spring的源碼中看了。Spring容器啟動時,ApplicationContext接口的實現類AnnotationConfigApplicationContext會執行refresh方法,往BeanFactory註冊bean就在此方法完成。我們看到這個refresh是核心。我們進入到這個源碼中看看:

Springboot中的javaConfig詳解(基於Spring5.2)

我截取了其中一部分的源碼,在裡面有一個方法很關鍵,那就是invokeBeanFactoryPostProcessors,意思是我們Spring容器首先會初始化BeanFactory,然後激活各種beanFactory處理器,也就是執行invokeBeanFactoryPostProcessors,我們看看這個方法:

Springboot中的javaConfig詳解(基於Spring5.2)

在這個方法的內部的核心是ConfigurationClassPostProcessor,這個方法看到@Configuration,就會開啟類的加載,這裡也就是bean的加載。剩下的越挖越深,源碼也越來越深。大體步驟我們可以總結一下:

ConfigurationClassPostProcessor處理器解析@configuration配置類主要過程:

(1)Spring容器初始化時註冊ConfigurationClassPostProcessor

(2)Spring容器初始化執行refresh()方法中調用ConfigurationClassPostProcessor

(3)ConfigurationClassPostProcessor處理器藉助ConfigurationClassParser完成配置類解析

(4)ConfigurationClassParser配置內解析過程中完成嵌套的MemberClass、@PropertySource註解、@ComponentScan註解(掃描package下的所有Class並進行迭代解析,主要是@Component組件解析及註冊)、@ImportResource、@Bean等處理

(5)接下來完成@Bean註冊, @ImportResource指定bean的註冊以及@Import的bean註冊

(6)有@Bean註解的方法在解析的時候作為ConfigurationClass的一個屬性,最後還是會轉換成BeanDefinition進行處理, 而實例化的時候會作為一個工廠方法進行Bean的創建

現在大致應該明白了,其實一句話說完,還是想辦法識別註解,完成和XML一樣的功能。


分享到:


相關文章: