工做中是否有這樣的場景?一個軟件系統會同時有多個不一樣版本部署,好比我如今作的IM系統,同時又做爲公司的技術輸出給其餘銀行,不一樣的銀行有本身的業務實現(好比登錄驗證、用戶信息查詢等); 又或者你的工程裏依賴了公司的二方包A,A又依賴了B...這些jar包裏的組件都是經過Spring容器來管理的,若是你想改B中某個類的邏輯,可是又不可能讓架構組的人幫你打一份特殊版本的B;怎麼辦呢?是否能夠考慮下直接把Spring容器裏的某個組件(Bean)替換成你本身實現的Bean?git
Spring框架超強的擴展性毋庸置疑,咱們能夠經過BeanPostProcessor來簡單替換容器中的Bean。github
@Component public class MyBeanPostProcessor implements ApplicationContextAware, BeanPostProcessor { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("defaultConfig")) { // 若是遇到須要替換的Bean,咱們直接換成本身實現的bean // 這裏的myConfig要繼承自defaultConfig,不然引用的地方會報錯 return applicationContext.getBean("myConfig"); } return bean; } }
優勢:spring
缺點:架構
Spring實際上就是一個容器,底層其實就是一個ConcurrentHashMap。若是要替換Map中的Entry,再次調用put方法設置相同的key不一樣的value就能夠了。同理,若是要替換Spring容器中的Bean組件,那麼咱們從新定義一個同名的Bean並註冊進去就能夠了。固然直接申明兩個同名的Bean是過不了Spring中ClassPathBeanDefinitionScanner
的檢查的,這時候須要咱們作一點點擴展。
app
目前的想法是直接重寫checkCandidate
方法,經過判斷Bean的類上是否有@Replace註解,來決定是否經過檢查。
依次往上擴展就到了ConfigurationClassPostProcessor
,這是Spring中很是重要的一個容器後置處理器BeanFactoryPostProcessor(上面咱們用的是Bean後處理器:BeanPostProcessor),重寫processConfigBeanDefinitions方法就能夠引入本身實現的ClassPathBeanDefinitionScanner。
具體細節能夠參考:https://github.com/hiccup234/spring-ext.git框架
直接在項目中增長以下座標(Maven中央倉庫),目前這個版本是對Spring的5.2.2.RELEASE作擴展,新版本的Spring其相對3.X、4.X有部分代碼變更。ide
<dependency> <groupId>top.hiccup</groupId> <artifactId>spring-ext</artifactId> <version>5.2.2.0-SNAPSHOT</version> </dependency>
對Spring Boot中的SpringApplication
作一點擴展,將上面擴展的ConfigurationClassPostProcessor
註冊到容器中。
聲明一個本身的類,而後繼承須要替換的Bean的類型(這樣就能夠重寫原Bean中的某些方法,從而添加本身的處理邏輯),而後用@Replace("defaultConfig")修飾,以下:
經過ExtSpringApplication啓動,能夠看到,實際Spring容器中的Bean已經替換成咱們本身實現的Bean組件了。
post