水稻:這两天看了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不了解一下嗎?
留言
張貼留言