Spring:BeanDefinition&PostProcessor不瞭解一下嗎?

渠成發表於2020-06-15

水稻:這兩天看了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的生命週期的時候我們們還會說到這些東西。到時候再刷一遍

 

相關文章