聊聊Spring中的那些擴充套件機制
前方高能預警:本文將會有大量程式碼出沒。
1.背景
在看一些框架原始碼的時候,可以看見他們很多都會和Spring去做結合。舉個例子dubbo的配置:
很多人其實配置了也就配置了,沒有去過多的思考:為什麼這麼配置spring就能識別,dubbo就能啟動?
如果你也需要做一個框架和Spring結合,或者你想知道Spring其他框架是如何和Spring做結合的,那麼你應該瞭解一下Spring的擴充套件機制。
2.如何擴充套件
本篇文章想從Spring的兩個流程去介紹如何擴充套件,一個是容器初始化流程,一個是Bean的建立流程進行將。
2.1 容器的初始化
要想使用Spring,第一步肯定是需要先讓容器初始化。在AbstractApplicationContext中有一個refresh方法定義了容器如何進行重新整理:
在refresh中的具體流程如下圖:
其中比較常見的擴充套件在載入BeanDefinition中和執行BeanPostProcessor。下面講述一下如何進行這兩個的擴充套件。
2.1.1 載入BeanDefinition
在介紹載入BeanDefinition之前,先讓我們瞭解一下什麼是BeanDefinition,顧名思義BeanDefinition描述Bean的資訊的,比如他的class資訊,屬性資訊,是否是單例,是否延遲載入等。
如何載入呢?一般有兩種手段,一個是透過我們的xml,一個是透過一些擴充套件手段。
xml載入如下:
我們在spring的XML中配置這樣一個bean的定義,他會進行解析然後轉換成我們的BeanDefinition。
還有種方式是透過XML schema擴充套件的方式,關於xsd的一些詳細介紹可以參考這篇文章:Spring中的XML schema擴充套件機制。有些同學會問不是還有個註解的方式嗎?我們在學的時候一般書上都寫XML和註解兩種方式,註解其實也是使用了XML schema的擴充套件機制,等會我會細講。
2.1.1.1 XML schema擴充套件
什麼是XML schema的擴充套件呢?
Spring允許你自己定義XML的的結構並且可以用自己的bean解析器進行解析。這裡參考一下Spring中的XML schema擴充套件機制進行自定義擴充套件的4個步驟:
編寫一個 XML schema 檔案描述的你節點元素。 在resources/META-INF/目錄下定義demo.xsd檔案。這裡定義了一個demo的節點元素,其中定義了一個name欄位。
編寫一個 NamespaceHandler 的實現類
編寫一個或者多個 BeanDefinitionParser 的實現 (關鍵步驟).
註冊上述的 schema 和 handler。 在resources/META-INF/ 目錄下面建立spring.handler檔案輸入:
http\://
,這一步將我們之前的標籤的url對映到我們NamespaceHandler。 再建立一個spring.schemas檔案,輸入:
http\://
這一步將xsd的url進行了對映。
回到註解,大家配置註解的時候一般都是使用下圖進行配置:
但是可以看見其依然是使用XML schema擴充套件進行處理,在Spring中有個叫ContextNamespaceHandler,註冊很多解析器:其中有一個解析器是compnent-scan,在他的parse方法中定義瞭如何進行註解掃描,獲取註解:
利用這個擴充套件機制的還有AOP,MVC,Spring-Cache以及我們的一些開源框架比如Dubbo等。
2.1.1.2 BeanFactoryPostProcessor擴充套件
這個機制可以讓我們在真正的例項化Bean之前對BeanDefinition進行修改。
這裡我舉例一個實戰的例子,想必大家很多都配置過資料庫連線池吧,這裡拿Druid來舉例:
然後我們建立一個druid.properties輸入:
url=jdbc:mysql://localhost:3306/testusername=rootpassword=123456
對於這種配置自己玩玩已經滿足,但是在公司有個問題,密碼放在專案中明碼儲存,這樣是不行的,別人只要獲得了你專案的檢視許可權那麼密碼就會被洩漏,所以一般的公司會有一個統一的密碼儲存服務,只有足夠的許可權才能夠使用,那麼我們可以把密碼放在統一儲存服務中,透過對服務的呼叫才能進行密碼的使用,那麼我們怎麼把從遠端服務中獲取到的密碼注入到我們Bean中呢?那麼就要使用我們的BeanFactoryPostpRrocessor,下面的程式碼繼承PropertyPlaceholderConfigurer(BeanFactoryPostpRrocessor的實現類):
在XML中有:
透過這種方式我們可以有幾個好處:
設定統一配置中心,那麼我們不需要修改我們專案中的檔案,只需要在配置中心頁面中修改即可。
設定統一密碼中心,那麼我們不需要暴露明文在專案中,密碼如何保護那麼就直接丟給密碼中心即可。
2.2 Bean的建立
一般我們在API中獲取一個Bean都會如下操作:
透過GetBean操作進行獲取,前面我們講到過如果是非延遲載入的單例Bean那麼會在容器重新整理的時候進行載入,如果是延遲載入的Bean那麼會在我們獲取Bean的時候根據BeanDefinition進行載入。 首先在AbstractBeanFactory有兩個方法一個是doCreate,一個是create用來描述如何建立一個Bean。這裡說一下單例Bean是如何建立的:
doCreateBean操作流程如下圖:
可以看見真正的建立bean的操作在CreateBean中,對於真正的建立Bean有如下流程:
。
2.2.1 Aware介面
Spring提供了很多Aware介面用於進行擴充套件,透過Aware我們可以設定很多想設定的東西:
invokeAwareMethod提供了三種最基本的Aware,如果是ApplicationContext的話那麼在ApplicationContextAwareProcessor又進行了一輪Aware注入。
BeanNameAware:如果Spring檢測到當前物件實現了該介面,會將該物件例項的beanName設定到對錢物件例項中。
BeanClassLoaderAware:會將載入當前Bean的ClassLoader注入進去。
BeanFactoryAware:將當前BeanFactory容器注入進去。
如果使用ApplicaitonContext型別的容器的話又會有下面幾種:
EnvironmentAware:將上下文中Enviroment注入進去,一般獲取配置屬性時可以使用。
EmbeddedValueResolverAware:將上下文中EmbeddedValueResolver注入進去,一般用於引數解析。 ResourceLoaderAware:將上下文設定進去。
ApplicationEventPublisherAware:在ApplicationContext中實現了ApplicationEventPublisher介面,所以可以將自己注入進去。
MessageSourceAware:將自身注入。
ApplicationContextAware:這個是我們見的比較多的,會將自身容器注入進去。
2.2.2 BeanPostProcessor
在前面我們說過BeanFactoryPostProcessor,這兩個名字很像,BeanFactoryPostProcessor是用來對我們BeanFactory中的BeanDefinition進行處理,此時Bean還未生成。而BeanPostProcessor用來對我們生成的Bean進行處理。
在BeanPostProcessor分為兩個方法,一個是用於初始化前置處理,一個是初始化用於後置處理。
有一種特殊的BeanPostProcessor,InstantiationAwareBeanPostProcessor,其會在我們例項化流程之前,如果實現了這個介面,那麼就會使用其返回的物件例項,不會進入後續流程。
實戰:BeanPostProcessor有什麼用呢?
如果你有一個需求,打點專案中方法每個方法的執行時常,你很容易想到用AOP去做,如果不用AOP的話那麼你可以使用BeanPostProcessor的後置處理方法,將對應的每個Bean都進行動態代理。
2.2.3 InitializingBean/init-method
Spring提供了我們對Bean進行初始化邏輯的擴充套件:
實現InitalizingBean介面: 在afterPropertiesSet()方法中我們可以寫入我們的初始化邏輯。
透過xml方式:
在init-method中定義了我們初始化方法。
2.2.4 DisposableBean/destory-method
俗話說,生與死輪迴不止。那麼我們有了生的擴充套件,自然Spring提供了死的擴充套件。我們也可以透過下面兩個擴充套件來實現我們銷燬的邏輯:
DisposableBean: 實現DisposableBean介面
實現destroy方法即可。
實現XML: 在destroy-method中定義銷燬方法。
PS:在我們Spring容器中如果要在JVM關閉時自動呼叫關閉的方法那麼我們可以((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();註冊關閉鉤子,這樣在關閉JVM的時候我們的Bean也能安全銷燬。
3.總結
本篇文章從Spring容器啟動原理,以及Bean的初始化原理介紹,引出了多個基本的擴充套件點。當然這部分擴充套件點還僅僅是Spring中的一部分,感興趣的可以閱讀Spring的文件,或者閱讀Spring原始碼。如果能掌握這些擴充套件,以後自己造輪子的時候和Spring結合這些擴充套件是不能少的。
最後打個廣告,如果你覺得這篇文章對你有文章,可以關注我的技術公眾號,最近作者收集了很多最新的學習資料影片以及面試資料,關注之後即可領取,你的關注和轉發是對我最大的支援,O(∩_∩)O
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31555607/viewspace-2214762/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 聊聊spring的那些擴充套件機制Spring套件
- 聊聊 Spring 的 XML Schema 擴充套件機制的使用方式SpringXML套件
- Spring 中的 XML schema 擴充套件機制SpringXML套件
- Spring容器擴充套件機制Spring套件
- 聊一聊 Spring 中的擴充套件機制(一)Spring套件
- Spring系列-XML schema擴充套件機制SpringXML套件
- 聊一聊 Spring 中的擴充套件機制(二) - NamespaceHandlerSpring套件namespace
- 聊聊Dubbo - Dubbo可擴充套件機制實戰套件
- 聊聊Dubbo – Dubbo可擴充套件機制原始碼解析套件原始碼
- 聊聊Spring擴充套件點BeanPostProcessor和BeanFactoryPostProcessorSpring套件Bean
- MOSN 擴充套件機制解析套件
- TLS擴充套件的那些事TLS套件
- Spring Cloud 中自定義外部化擴充套件機制原理及實戰SpringCloud套件
- 緣起 Dubbo ,講講 Spring XML Schema 擴充套件機制SpringXML套件
- 淺析Dubbo的SPI擴充套件機制套件
- 1.2 - Laravel 5.6 - Extend 擴充套件機制Laravel套件
- 重構 - 設計API的擴充套件機制API套件
- Spring IoC 容器的擴充套件Spring套件
- 使用Kotlin擴充套件函式擴充套件Spring Data案例Kotlin套件函式Spring
- spring bean 擴充套件方式SpringBean套件
- 回覆關鍵詞的無限擴充套件機制套件
- 從EventBus學習擴充套件Weex事件機制套件事件
- Dubbo原始碼分析(一)Dubbo的擴充套件點機制原始碼套件
- Spring擴充套件介面(4):InstantiationAwareBeanPostProcessorSpring套件Bean
- Spring擴充套件介面(2):BeanDefinitionRegistryPostProcessorSpring套件Bean
- Spring擴充套件之二:ApplicationListenerSpring套件APP
- 那些離不開的 Chrome 擴充套件外掛Chrome套件
- 「Android」分析EventBus原始碼擴充套件Weex事件機制Android原始碼套件事件
- 圖解Dubbo,6 種擴充套件機制詳解圖解套件
- 聊聊Dubbo(五):核心原始碼-SPI擴充套件原始碼套件
- Spring Boot中的Mongodb多資料來源擴充套件Spring BootMongoDB套件
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- Dubbo原始碼分析(三)Dubbo中的SPI和自適應擴充套件機制原始碼套件
- Solon詳解(五)- Solon擴充套件機制之Solon Plugin套件Plugin
- Android Handler機制之訊息池的擴充套件 SimplePool與SynchronizedPoolAndroid套件synchronized
- shell中擴充套件命令套件
- Spring Boot中如何擴充套件XML請求和響應的支援Spring Boot套件XML
- sql中的擴充套件學習SQL套件