某個平凡熟悉的早上,傳來測試同窗的一陣哀嚎:那個誰!你提測的代碼連運行都不能運行,苦澀。java
我默不做聲,由於主項目尚未徹底服務化,主項目的總體war
包太大,加上歷來沒有講究過,開發同窗跑一個測試用例,每每啓動Spring
就要花一分半鐘,哪裏有心情按規範跑單測呢?同問了幾個開發同窗也都有一樣的痛點,感受解決單測環境刻不容緩,古人云:工欲善其事,必先利其器,對吧?spring
Debug
級別沒錯,這是咱們須要作的第一步最重要的步驟,開啓單測,把日誌打到一個文件裏,從頭擼到尾,究竟你這加載的一分半鐘究竟幹嗎了~數據庫
一些Spring配置初始化
根據ComponentScan掃路徑的Class類,加入待注入候選列表
根據Mapper掃路徑的Class類,加入待注入候選列表
對掃出來的Mapper建立MapperFactoryBean
建立注入@Configuration裏@Bean註解的Bean的BeanDefinitions
預加載一些Bean
一些組件例如,PostProcessor、Advisor初始化
一些中間件例如數據庫、緩存、消息隊列加載
掃描的Bean的初始化,依賴注入。。
Bean的PostConstruct開始跑
....//可能不是很全,列舉了其中一部分
複製代碼
默默的看了眼日誌,20M,媽耶,引了一個
ApplicationContextAware
看了一下
BeanFactory
,好吧,加載了1500個
Bean
,
Spring
默認的Ioc容器會把全部的Bean在啓動時,都加載成功,首先想到的措施是讓
Bean懶加載,按需加載,不用的就不加載嘛,很簡單!
簡單的網上衝浪了一下,咱們須要將緩存
註解法:@ComponentScan(value = "com.evanyz",lazyInit = true) //將這個配置設爲true
//xml裏是beans裏有一個default-lazy-init標籤
複製代碼
但是設置成功以後,徹底不生效,仍是1500個,嘗試許久,仍是沒生效,感受很懵逼,甚至都有點開始懷疑Spring
了。bash
排查許久後,忽然發現爲何Debug
的時候,會報一些該Bean重複已存在忽略的錯,忽然靈光一現。 MD,咱們項目裏寫代碼根本不講究,每個子項目裏,例如common
、biz
都含有Spring
的初始化文件。app
也就是說,從這個初始化配置以後,繼續掃其餘的配置文件,仍是會繼續加載,致使以前的配置失效。。工具
舉例:
我在test的初始化類裏配置了 @ComponentScan(value = "com.evanyz",lazyInit = true) ,
當他掃到biz子項目的時候,發現另一個Spring的配置文件是
@ComponentScan(value = "com.evanyz")
這時候懶加載會被覆蓋掉,就不生效了。。
複製代碼
這時候想到的辦法就是 在test配置里加上一些操做,解釋見註解測試
@ComponentScan(
//掃包
value = {com.evanyz"},
//排除一些Bean
excludeFilters = {
//作點小優化,讓他把一些在跑單測時的擴展點不要注入
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
SmsServicePostProcessor.class, CatUrlPostProcessor.class,
}),
//按政策排除,把一些其餘項目裏的Spring配置去掉
@ComponentScan.Filter(type = FilterType.REGEX, pattern = {
"com\\.evanyz\\.test\\..*",
"com\\.evanyz\\.biz\\.springconfig..*",
"com\\.evanyz\\.common\\.springconfig..*",
"com\\.evanyz\\.common\\.cat..*"
}),
//最後清掉了發現,仍是有一些配置被加載了
//一不作二不休,我全乾掉,搞白名單還不行嗎?哭哭
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {
ComponentScan.class, Configuration.class, ImportResource.class
}),
}, lazyInit = true
)
複製代碼
通過以上的一頓操做,Spring終於懶加載了,直觀的看一下以後的Debug
,瘦身了3倍,爽! 優化
雖然Spring
已懶加載,可是依賴很亂,每每依賴一個服務,又要注入不少的類,並且不少的業務的類,都寫了@PostConstruct
,若是裏面包含業務代碼,例如查庫啊之類的,你就呵呵吧。一次Spring啓動能給你跑100條Sql,能不慢嗎?ui
來,壯士斷腕,把這些毒瘤,會預先加載的類,選一些不重要的在單測不須要用的都作個Mock,不要讓這個拖垮咱們的環境!
這時候,其實一次單測已經在30s就能夠搞定了,可是本着有點追求的想法,仍是想再優化一下。
忽然發現有一個可疑的日誌
咱們用的Cat
作監控,咱們項目裏有不少Cat
打點的工具類,只要跑到一個打點上,Cat就會開始加載(明明連不上),可是這一步驟估計是IO
之類的東西,加載一下竟然花了10幾秒,個人天,確定要幹掉!
怎麼幹呢?由於這些打點是耦合在代碼裏的,很差動,這時候想到的解決方案就是看看Cat
能不能關掉,後來衝浪了一番,發現咱們這個舊版本沒辦法關。怎麼辦呢?被逼出來的
classLoader默認會讀同名最近的那個類
複製代碼
最後跑了一下單測,16s
,好爽!
自從單測優化以後,後面制定規範讓你們交付測試的時候本身先跑遍單測,這樣就能有效的避免由於一些小錯誤返工 四、5次的尷尬,並且單測測的更全,更不容易出錯,利已利民。
這裏貼一下單測的核心類的註釋:
多點時間陪陪家人
我:爽嗎?我問對面的開發。
他:太爽了!
我笑了笑,深藏功與名(:
複製代碼