跳到主要內容

【Spring】BeanDefinition&PostProcessor不了解一下嗎?

水稻:這两天看了BeanDefinition和BeanFactoryPostProcessor還有BeanPostProcessor的源碼。要不要了解一下


菜瓜:six six six,大佬請講


水稻:上次我們說SpringIOC容器是一個典型的工廠模式



  • 假如我們把Spring比作一個生產模型的大工廠,那麼.class文件就是原材料。而BeanDefinition就是創建模型的模具。不管是傳統的XML還是後面的註解,Spring在啟動的時候都會創建一個掃描器去掃描指定目錄下的.class文件,並根據文件的註解,實現的接口以及成員變量將其封裝一個個的BeanDefinition。

    • 比較重要的屬性有id,class,構造函數封裝類,屬性封裝類,factoryMethod等


  • 在對象初始化之前Spring會完成BeanDefinition對象的解析並將其裝入List容器beanDefinitionNames中,然後開始遍歷該容器並根據BeanDefinition創建對象


菜瓜:sodasinei,BeanDefinition我了解了。它是創建bean的模板,類似於java創建對象依賴的class一樣。那還有兩個很長的單詞是啥呢?


水稻:忽略掉後面老長的後綴,我們看BeanFactory和Bean是不是很親切。PostProcessor被翻譯成後置處理器,暫且我們把它看成是處理器就行



  • BeanFactory是bean工廠,它可以獲取並修改BeanDefinition的屬性,進而影響後面創建的對象。

  • Bean就是Spring的對象,這些個處理器才是真正處理bean對象的各個環節的工序,包括屬性,註解,方法


菜瓜:有了模糊的概念,不明覺厲


水稻:來,看demo


package com.vip.qc.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
* 獲取初始化好的BeanFactory,此時還未進行bean的實例化
*
*
@author QuCheng on 2020/6/14.
*/
@Component
public class BeanFactoryPostProcessorT implements BeanFactoryPostProcessor {

public static final String BEAN_NAME = "processorT";

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition initializingBeanT
= beanFactory.getBeanDefinition(BEAN_NAME);
MutablePropertyValues propertyValues
= initializingBeanT.getPropertyValues();
String pName
= "a";
System.out.println(
"BeanFactoryPostProcessor a " + propertyValues.getPropertyValue(pName) + " -> 1");
propertyValues.addPropertyValue(pName,
"1");
}
}


package com.vip.qc.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
*
@author QuCheng on 2020/6/14.
*/
@Component
public class BeanPostProcessorT implements BeanPostProcessor {

public static final String beanNameT = "processorT";

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanNameT.equals(beanName)) {
ProcessorT processorT
= ((ProcessorT) bean);
System.out.println(
"BeanPostProcessor BeforeInitialization a:" + processorT.getA() + "-> 3");
processorT.setA(
"3");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanNameT.equals(beanName)){
ProcessorT processorT
= ((ProcessorT) bean);
System.out.println(
"BeanPostProcessor AfterInitialization a:" + processorT.getA() + "-> 4");
processorT.setA(
"4");
}
return bean;
}

}


package com.vip.qc.postprocessor;

import org.springframework.stereotype.Component;

/**
*
@author QuCheng on 2020/6/14.
*/
@Component
public class ProcessorT {

public ProcessorT() {
System.out.println(
"ProcessorT 無參構造 a:" + a + "-> 2" );
a
= "2";
}

private String a;

public String getA() {
return a;
}

public void setA(String a) {
this.a = a;
}

@Override
public String toString() {
return "ProcessorT{" +
"a='" + a + '\'' +
'}';
}
}

// 測試類
@Test
public void test() {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext("com.vip.qc.postprocessor");
ProcessorT processorT
= (ProcessorT) context.getBean("processorT");
System.out.println(processorT);
}

// 結果
BeanFactoryPostProcessor a null -> 1
ProcessorT 無參構造 a:
null-> 2
BeanPostProcessor BeforeInitialization a:
1-> 3
BeanPostProcessor AfterInitialization a:
3-> 4
ProcessorT{a
='4'}


  • BeanFactoryPostProcessor在對象還未初始化前可以拿到對象的BeanDefinition對其設置屬性值

  • 過程中我們分別對屬性a設置了1,2,3,4的值。最後我們拿到的值為4


菜瓜:好像看懂了。BeanFactoryPostProcessor可以拿到BeanFactory對象,獲取裏面所有的BeanDefinition並可對其進行干預。BeanPostProcessor其實是在bean已經被創建完成之後進行加工操作


水稻:沒錯。這是我們自己進行干預的demo。限於篇幅有限,你可以去看一下Spring自己對於這兩個接口的實現源碼。比較重要的推薦下面幾個



  • ConfigurationClassPostProcessor 實現BeanFactoryPostProcessor子接口

    • 完成對@Configuration、@Component、@ComponentScan、@Bean、@Import、@ImportSource註解的搜集和解析

    • @Bean註解會被封裝成所在Bean的BeanDefinition中的factoryMethod屬性中,單獨進行實例化


  • CommonAnnotationBeanPostProcessor 實現 BeanPostProcessor

    • 完成@PostConstruct@PreDestroy@Resource註解的搜集和解析工作

    • @PostConstruct會在對象初始化且屬性渲染完成後進行

    • @Resource註解(參照下面)


  • AutowiredAnnotationBeanPostProcessor 實現 BeanPostProcessor

    • 完成@Autowired@Value註解的搜集和解析工作

    • 在對象初始化完成之後會先進行註解的搜集,然後進行屬性渲染調用populateBean方法,使用策略模式調用實現接口對註解進行解析,有@Autowired和@Value註解會調用getBean方法發起對依賴屬性的注入


  • AbstractAutoProxyCreator的入口類也是實現的BeanPostProcessor


菜瓜:你放心,我不會看的。這麼複雜的東西,聽着都費勁


水稻:不愧是你!有機會聊bean的生命周期的時候咱們還會說到這些東西。到時候再刷一遍


 


總結:



  • BeanDefinition是spring容器創建對象的模板,定義了bean創建的細節

  • BeanFactoryPostProcessor可以拿到整個容器對象,當然也能修改BeanDefinition,所以能直接操作bean的創建

  • BeanPostProcessor執行的時候bean已經創建完成了,我們可以拿到想要的對象進行干預和設值等操作

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】



※超省錢租車方案



※別再煩惱如何寫文案,掌握八大原則!



※回頭車貨運收費標準



※教你寫出一流的銷售文案?



※產品缺大量曝光嗎?你需要的是一流包裝設計!



※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益



Orignal From: 【Spring】BeanDefinition&PostProcessor不了解一下嗎?

留言

這個網誌中的熱門文章

Python 併發總結,多線程,多進程,異步IO

1 測量函數運行時間 import time def profile(func): def wrapper(*args, ** kwargs): import time start = time.time() func( *args, ** kwargs) end = time.time() print ' COST: {} ' .format(end - start) return wrapper @profile def fib(n): if n<= 2 : return 1 return fib(n-1) + fib(n-2 ) fib( 35 )   2 啟動多個線程,並等待完成   2.1 使用threading.enumerate() import threading for i in range(2 ): t = threading.Thread(target=fib, args=(35 ,)) t.start() main_thread = threading.currentThread() for t in threading.enumerate(): if t is main_thread: continue t.join()   2.2 先保存啟動的線程 threads = [] for i in range(5 ): t = Thread(target=foo, args= (i,)) threads.append(t) t.start() for t in threads: t.join()   3 使用信號量,限制同時能有幾個線程訪問臨界區 from threading import Semaphore import time sema = Semaphor...

高雄十大包子名店出爐

, 圖文:吳恩文 高雄包子大賽落幕了,我只能就我個人意見, 介紹一下前十名這些包子,但是不能代表其他四位評審的意見,雖然身為評審長,我通常不會第一個表示意見,以免影響其他評審, 我主要工作是負責發問。   這次參賽的素包子很少,而且都不夠細致,又偏油,我不愛, 但是第一名的甜芝麻包-熔岩黑金包,竟然是素食得名- 漢來蔬食巨蛋店。   這包子賣相太好,竹炭粉的黑色外皮刷上金粉,一上桌,眾人驚呼, 搶拍照,內餡是芝麻餡,混一點花生醬增稠,加入白糖芝麻油, 熔岩爆漿的程度剛剛好,我一直以為芝麻要配豬油才行、 但是選到好的黑芝麻油一樣不減香醇, 當下有二位評審就想宅配回家。   尤其特別的是,黑芝麻餡室溫易化,師傅必須要輪班躲在冷藏室內, 穿著大外套才能包,一天包不了多少,我笑說,漢來美食,集團餐廳那麼多,實力雄厚,根本是「 奧運選手報名參加村裡運動會」嘛,其他都是小包子店啊, 但是沒辦法,顯然大家都覺得它好看又好吃, 目前限定漢來蔬食高雄巨蛋店,二顆88元,可以冷凍宅配, 但是要排一陣子,因為供不應求,聽說,四月份, 台北sogo店開始會賣。   第二名的包子,左營寬來順早餐店,顯然平易近人的多,一顆肉包, 十塊錢,是所有參賽者中最便宜的,當然,個頭也小, 它的包子皮明顯和其他不同,灰灰的老麵,薄但紮實有嚼勁, 肉餡新鮮帶汁,因為打了些水,味道極其簡單,就是蔥薑,塩, 香油,薑味尤其明顯,是老眷村的味道, 而特別的是老闆娘是台灣本省人, 當年完全是依據眷村老兵的口味一步一步調整而來,沒有加什麼糖、 五香粉,胡椒粉,油蔥酥。就是蔥薑豬肉和老麵香,能得名, 應該是它的平實無華,鮮美簡單,打動人心。   這是標準的心靈美食,可以撫慰人心,得名之前,寛來順已經天天排隊,現在,恐怕要排更久了, 建議大家六七點早點上門。   第三名,「專十一」很神奇,我記得比賽最後, 大家連吃了幾家不能引起共鳴的包子,有些累,到了專十一, 就坐著等包子,其他評審一吃,就催我趕快試,我一吃, 也醒了大半。   它的包子皮厚薄適中,但是高筋麵粉高些,老麵加一點點酵母, 我心中,它的皮屬一屬二,至於餡又多又好吃,蛋黃還是切丁拌入, 不是整顆放,吃起來「美味、均衡、飽滿」。一顆二十元。   老闆是陸軍專科十一期畢業取名專十一,...

韋伯連續劇終於更新 期待第一季順利完結

  地球天文學界的跳票大王詹姆斯·韋伯空間望遠鏡 (James Webb Space Telescope,縮寫為 JWST)自 1996 年以來斷斷續續不按劇本演出的連續劇終於讓焦慮的觀眾們又等到了一次更新:五層遮陽罩測試順利完成。 裝配完成的韋伯望遠鏡與好夥伴遮陽罩同框啦。Credit: NASA   嚴格的測試是任何空間任務順利成功的重中之重。遮陽罩,這個韋伯望遠鏡異常重要的親密夥伴,要是無法正常運轉的話,韋伯的這一季天文界連續劇說不準就要一直拖更了。   詹姆斯·韋伯空間望遠鏡是歷史上造出的最先進的空間望遠鏡。它不僅是一架紅外望遠鏡,還具有特別高的靈敏度。但想要達到辣么高的靈敏度來研究系外行星和遙遠的宇宙童年,韋伯童鞋必須非常"冷靜",體溫升高的話,靈敏度會大大折損。這個時候,遮陽罩就要大顯身手啦。   遮陽罩在韋伯的設計中至關重要。韋伯望遠鏡會被發射到拉格朗日 L2 點,運行軌道很高,遠離太陽、地球與月球。太陽是韋伯的主要熱量干擾的來源,其次是地球與月球。遮陽罩會有效阻斷來自這三大熱源的能量並保護韋伯維持在工作溫度正常運轉。這個工作溫度指的是零下 220 攝氏度(-370 華氏度;50 開爾文)。 上圖中我們可以看出,韋伯望遠鏡的配置大致可分為兩部分:紅色較熱的一面溫度為 85 攝氏度,藍色較冷的一面溫度達到零下 233 攝氏度。紅色的這部分中,儀器包括太陽能板、通信設備、計算機、以及轉向裝置。藍色部分的主要裝置包括鏡面、探測器、濾光片等。Credit: STSci.   遮陽罩的那一部分和望遠鏡的鏡面這部分可以產生非常極端的溫差。遮陽的這面溫度可以達到 110 攝氏度,足以煮熟雞蛋,而背陰處的部分溫度極低,足以凍結氧氣。   工程師們剛剛完成了五層遮陽罩的測試,按照韋伯在 L2 時的運行狀態安裝了遮陽罩。L2 距離地球約 160 萬公里。NASA 表示這些測試使用了航天器的自帶系統來展開遮陽罩,測試目前都已成功完成。韋伯望遠鏡遮陽罩負責人 James Cooper 介紹說這是遮陽罩"第一次在望遠鏡系統的电子設備的控制下展開。儘管這個任務非常艱巨,難度高,但測試順利完成,遮陽罩展開時的狀態非常驚艷"。   遮陽罩由五層 Kapton 製成。Kapton 是一種聚酰亞胺薄膜材料, 耐高溫絕...