一文吃透Spring Boot擴充套件之BeanFactoryPostProcessor
概述
BeanFactoryPostProcessor
是Spring中一個相當重要的擴充套件點,擴充套件點就是能讓我們在Spring容器以及Bean生命週期的各個階段中可以進行修改擴充套件。
什麼是BeanFactoryPostProcessor
BeanFactoryPostProcessor
, 翻譯過來大致是Bean的工廠處理器,顧名思義,可以理解為它對Bean工廠中Bean定義(BeanDefintion
)進行修改, 它的執行時機:BeanFactory標準初始化之後,所有的Bean定義已經被載入,但標準Bean的例項還沒被建立(不包括BeanFactoryPostProcessor
型別)。該方法通常用於修改bean的定義,Bean的屬性值等,甚至可以在此快速初始化Bean。
而另外一個相關的擴充套件介面的BeanDefinitionRegistryPostProcessor
,繼承自BeanFactoryPostProcessor
,所有的Bean定義即將被載入,但Bean的例項還沒被建立時,也就是說,BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法執行時機先於BeanFactoryPostProcessor
的postProcessBeanFactory
方法。
區別於一個很類似的擴充套件介面BeanPostProcessor
, 它的執行時機實在Bean初始化前後,新增一些自己想要的邏輯。
小結一下,上面關聯的擴充套件介面執行順序如下:1.BeanDefinitionRegistryPostProcessor
,2.BeanFactoryPostProcessor
,3.BeanPostProcessor
。而BeanFactoryPostProcessor
主要是在標準的BeanDefinition
已經準備完畢,可以去修改已有的BeanDefinition
的相關屬性等。
如何使用BeanFactoryPostProcessor
- 新建一個測試bean
``` @Data @Component public class Student {
@Value("${user.username:alvin}")
private String username;
@Value("${user.age:12}")
private int age;
} ```
- 新建處理器實現
BeanFactoryPostProcessor
``` @Component @Slf4j public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.info("******************** TestBeanFactoryPostProcessor#postProcessBeanFactory ****************");
log.info("******************** bean的數量:[{}] ****************", beanFactory.getBeanDefinitionCount());
// 修改bean definition屬性資訊
BeanDefinition userBeanDef = beanFactory.getBeanDefinition("student");
userBeanDef.getPropertyValues().add("username", "cxw");
// 快速初始化Bean
User user = (User)beanFactory.getBean("student");
log.info("student name: [{}]", user.getUsername());
}
} ```
- 驗證結論
bean的屬性被成功被修改了。
原始碼解析
介面定義
``` /* * Factory hook that allows for custom modification of an application context's * bean definitions, adapting the bean property values of the context's underlying * bean factory. * *
Useful for custom config files targeted at system administrators that * override bean properties configured in the application context. See * {@link PropertyResourceConfigurer} and its concrete implementations for * out-of-the-box solutions that address such configuration needs. * *
A {@code BeanFactoryPostProcessor} may interact with and modify bean * definitions, but never bean instances. Doing so may cause premature bean * instantiation, violating the container and causing unintended side-effects. * If bean instance interaction is required, consider implementing * {@link BeanPostProcessor} instead. * *
Registration
*An {@code ApplicationContext} auto-detects {@code BeanFactoryPostProcessor} * beans in its bean definitions and applies them before any other beans get created. * A {@code BeanFactoryPostProcessor} may also be registered programmatically * with a {@code ConfigurableApplicationContext}. * *
Ordering
*{@code BeanFactoryPostProcessor} beans that are autodetected in an * {@code ApplicationContext} will be ordered according to * {@link org.springframework.core.PriorityOrdered} and * {@link org.springframework.core.Ordered} semantics. In contrast, * {@code BeanFactoryPostProcessor} beans that are registered programmatically * with a {@code ConfigurableApplicationContext} will be applied in the order of * registration; any ordering semantics expressed through implementing the * {@code PriorityOrdered} or {@code Ordered} interface will be ignored for * programmatically registered post-processors. Furthermore, the * {@link org.springframework.core.annotation.Order @Order} annotation is not * taken into account for {@code BeanFactoryPostProcessor} beans. * * @author Juergen Hoeller * @author Sam Brannen * @since 06.07.2003 * @see BeanPostProcessor * @see PropertyResourceConfigurer / @FunctionalInterface public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
} ```
介面的註釋很清楚的說明了它的作用和細節,大致有下面幾點:
- 該介面允許使用者自定義修改工廠bean中的BeanDefinition, 調整BeanDefinition的屬性值,甚至初始化Bean。比如內建的
PropertyResourceConfigurer
,就是修改beanDefinition的屬性為配置檔案的屬性。 - 該介面主要是用於修改BeanDefinition, 雖然也可以直接進行例項化Bean, 但是不建議這麼做,可能會造成其他未知的錯誤。
執行流程
其中核心邏輯是PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
方法,該方法的前面部分邏輯主要是處理BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法,也就是想BeanDefinition註冊中中心新增新的BeanDefinition。
```
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List
.......... 該部分是處理BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry相關邏輯,跳過, 可以看BeanDefinitionRegistryPostProcessor的解析
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// 獲取所有實現了BeanFactoryPostProcessor介面的bean name列表,前提是在BeanFactory的BeanDefinitions列表中包含對應的bean定義資訊。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 存放實現了PriorityOrdered介面的processor
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 存放實現了Ordered介面的processor
List<String> orderedPostProcessorNames = new ArrayList<>();
// 存放沒有實現排序的processor
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// 遍歷前面全量的bean name,將他們歸類,放到上面的容器中
for (String ppName : postProcessorNames) {
// 如果在第一階段已經被呼叫過,就不呼叫,第一階段主要是BeanDefinitionRegistryPostProcessor,它繼承了BeanFactoryPostProcessor,它會在第一階段呼叫。
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
// 首先執行實現了PriorityOrdered介面的processor,對它們進行排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 真實執行processor中的邏輯。
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
// 其次執行實現了Ordered介面的processor,對它們進行排序後執行processor中的邏輯。
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最後執行,沒有順序要求的processor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
//呼叫processors中的postProcessBeanFactory方法 private static void invokeBeanFactoryPostProcessors( Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanFactory(beanFactory);
postProcessBeanFactory.end();
}
}
```
小結
整個執行流程的原始碼還是比較清晰並且簡單的。重點提下下面兩個點:
- 我們自定義的BeanFactoryProcessor需要加上
@Component
等註解,為什麼?
看原始碼得知,String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
獲取所有實現了BeanFactoryPostProcessor的Bean Name, 前提所有的Bean都要被註冊到BeanDefinitionRegistry
, 通過新增@Component
, @Service
等註解,可以將對應的Bean定義資訊註冊到BeanFactory中,方便後面例項化Bean。 那麼它是在什麼地方註冊的呢?可以看下ConfigurationClassPostProcessor
類,它實現了BeanDefinitionRegistryPostProcessor
,會掃描所有@Component
, @Service
等註解,將對應的Bean Definition註冊到BeanFactory中。
- 執行順序問題
我們可以通過實現PriorityOrdered
, Ordered
介面,控制BeanFactoryProcessor
的執行順序,, 優先執行實現了PriorityOrdered
介面,其次是Ordered
,最後是沒有實現任何排序介面的processor。
內建的BeanFactoryPostProcessor
Spring內建了一個比較重要的BeanFactoryPostProcessor
是PlaceholderConfigurerSupport
, 實現從配置檔案中獲取屬性。
- TO BANK解決方案微服務架構的正確姿勢
- Java高效能序列化工具Kryo序列化
- 記一次記憶體洩漏引發的生產事故
- Zookeeper系列(三)——Zookeeper的ACL許可權控制
- 原始碼解析最流行的Validator框架——Hibernate Validator
- Zookeeper系列(一)——Zookeeper基礎之資料模型
- 一文帶你深入理解SpringBean生命週期之PostConstruct、PreDestroy詳解
- 一文帶你深入理解SpringBean生命週期之Aware詳解
- 一文吃透Spring Boot擴充套件之BeanFactoryPostProcessor
- 一文帶你瞭解Java Class的生命週期(類載入過程)