在此係列文章中,我總結了Spring幾乎所有的擴充套件介面,以及各個擴充套件點的使用場景。並整理出一個bean在spring中從被載入到最終初始化的所有可擴充套件點的順序呼叫圖。這樣,我們也可以看到bean是如何一步步載入到spring容器中的。
BeanDefinitionRegistryPostProcessor
1、概述
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException; }
BeanDefinitionRegistryPostProcessor為容器級後置處理器。容器級的後置處理器會在Spring容器初始化後、重新整理前執行一次。還有一類為Bean級後置處理器,在每一個Bean例項化前後都會執行。
通常,BeanDefinitionRegistryPostProcessor用於在bean解析後例項化之前透過BeanDefinitionRegistry對BeanDefintion進行增刪改查。
常見如mybatis的Mapper介面注入就是實現的此介面。
2、簡單案例
下面是一個示例,展示瞭如何實現動態的給spring容器新增一個Bean:
public class User {
String name;
String password;
}
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
@Component
public class DynamicBeanRegistration implements BeanDefinitionRegistryPostProcessor, Ordered {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(User.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
PropertyValue propertyValue1 = new PropertyValue("name", "張三");
PropertyValue propertyValue2 = new PropertyValue("password", "123456");
propertyValues.addPropertyValue(propertyValue1);
propertyValues.addPropertyValue(propertyValue2);
beanDefinition.setPropertyValues(propertyValues);
beanRegistry.registerBeanDefinition("user", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
System.out.println(beanDefinition.getBeanClassName());
User user = beanFactory.getBean(User.class);
System.out.println(user.getName());
System.out.println(user.getPassword());
}
@Override
public int getOrder() {
return 0;
}
}
輸出:
com.sandy.springex.beanfefinitionregistrypostprocessor.User
張三
123456
- 首先定義了一個名為"User"的Java類,包含了兩個屬性:name和password。
- 然後定義了一個名為"DynamicBeanRegistration"的元件(透過@Component註解),實現了BeanDefinitionRegistryPostProcessor介面和Ordered介面。
- 在postProcessBeanDefinitionRegistry方法中,建立了一個RootBeanDefinition物件,並設定其beanClass為User類。接著建立了一個MutablePropertyValues物件,並透過PropertyValue物件設定了name和password屬性的值。最後,將propertyValues設定到beanDefinition中,並使用beanRegistry註冊了一個名為"user"的BeanDefinition。
- 在postProcessBeanFactory方法中,透過beanFactory獲取了名為"user"的BeanDefinition,並輸出了其beanClassName。然後使用beanFactory獲取了一個User物件,並輸出了其name和password屬性的值。
該程式碼透過實現BeanDefinitionRegistryPostProcessor介面,在Spring容器啟動時動態註冊了一個名為"user"的Bean,並設定了其name和password屬性的值。在後續的BeanFactory初始化過程中,可以透過beanFactory獲取到該動態註冊的Bean,並訪問其屬性值。
當容器中有多個BeanDefinitionRegistryPostProcessor的時候,可以透過實現Ordered介面來指定順序:
@Override
public int getOrder() {
return 0; //值越小,優先順序越高
}
3、原始碼分析
- 在DynamicBeanRegistration打上斷點,啟動SpringApplication,可以看到左下角的呼叫鏈路。
- 紅框中5步都是在springboot中進行,最後super.refresh()是呼叫大家熟悉的spring的AbstractApplicationContext的refresh方法。
- 繼續向下看
- 接下來進入核心的invokeBeanFactoryPostProcessors方法,大概邏輯是先取出所有實現了BeanDefinitionRegistryPostProcessor介面的類,然後優先呼叫實現了PriorityOrdered介面的元件,再呼叫實現了Ordered介面的元件。
- 最後,遍歷呼叫BeanDefinitionRegistryPostProcessor元件postProcessBeanDefinitionRegistry方法