概述
BeanFactoryPostProcessor是Spring中一個相當重要的擴展點,擴展點就是能讓我們在Spring容器以及Bean生命周期的各個階段中可以進行修改擴展。
什么是BeanFactoryPostProcessor
BeanFactoryPostProcessor, 翻譯過來大致是Bean的工廠處理器,顧名思義,可以理解為它對Bean工廠中Bean定義(BeanDefintion)進行修改, 它的執(zhí)行時機:BeanFactory標準初始化之后,所有的Bean定義已經(jīng)被加載,但標準Bean的實例還沒被創(chuàng)建(不包括BeanFactoryPostProcessor類型)。該方法通常用于修改bean的定義,Bean的屬性值等,甚至可以在此快速初始化Bean。
而另外一個相關(guān)的擴展接口的BeanDefinitionRegistryPostProcessor,繼承自BeanFactoryPostProcessor,所有的Bean定義即將被加載,但Bean的實例還沒被創(chuàng)建時,也就是說,BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法執(zhí)行時機先于BeanFactoryPostProcessor的postProcessBeanFactory方法。
區(qū)別于一個很類似的擴展接口BeanPostProcessor, 它的執(zhí)行時機實在Bean初始化前后,添加一些自己想要的邏輯。
小結(jié)一下,上面關(guān)聯(lián)的擴展接口執(zhí)行順序如下:1.BeanDefinitionRegistryPostProcessor,2.BeanFactoryPostProcessor,3.BeanPostProcessor。而BeanFactoryPostProcessor主要是在標準的BeanDefinition已經(jīng)準備完畢,可以去修改已有的BeanDefinition的相關(guān)屬性等。
如何使用BeanFactoryPostProcessor
@Data@Componentpublic class Student { @Value(“${user.username:alvin}”) private String username; @Value(“${user.age:12}”) private int age;}
@Component@Slf4jpublic class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { log.info(“******************** TestBeanFactoryPostProcessor#postProcessBeanFactory ****************”); log.info(“******************** bean的數(shù)量:[{}] ****************”, 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 */@FunctionalInterfacepublic 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;}
接口的注釋很清楚的說明了它的作用和細節(jié),大致有下面幾點:
- 該接口允許用戶自定義修改工廠bean中的BeanDefinition, 調(diào)整BeanDefinition的屬性值,甚至初始化Bean。比如內(nèi)置的PropertyResourceConfigurer,就是修改beanDefinition的屬性為配置文件的屬性。
- 該接口主要是用于修改BeanDefinition, 雖然也可以直接進行實例化Bean, 但是不建議這么做,可能會造成其他未知的錯誤。
執(zhí)行流程
其中核心邏輯是PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法,該方法的前面部分邏輯主要是處理BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,也就是想BeanDefinition注冊中中心添加新的BeanDefinition。
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) { ………. 該部分是處理BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry相關(guān)邏輯,跳過, 可以看BeanDefinitionRegistryPostProcessor的解析 // Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them! // 獲取所有實現(xiàn)了BeanFactoryPostProcessor接口的bean name列表,前提是在BeanFactory的BeanDefinitions列表中包含對應(yīng)的bean定義信息。String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest. // 存放實現(xiàn)了PriorityOrdered接口的processorList priorityOrderedPostProcessors = new ArrayList(); // 存放實現(xiàn)了Ordered接口的processorList orderedPostProcessorNames = new ArrayList(); // 存放沒有實現(xiàn)排序的processorList nonOrderedPostProcessorNames = new ArrayList(); // 遍歷前面全量的bean name,將他們歸類,放到上面的容器中for (String ppName : postProcessorNames) { // 如果在第一階段已經(jīng)被調(diào)用過,就不調(diào)用,第一階段主要是BeanDefinitionRegistryPostProcessor,它繼承了BeanFactoryPostProcessor,它會在第一階段調(diào)用。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. // 首先執(zhí)行實現(xiàn)了PriorityOrdered接口的processor,對它們進行排序sortPostProcessors(priorityOrderedPostProcessors, beanFactory); // 真實執(zhí)行processor中的邏輯。invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered. // 其次執(zhí)行實現(xiàn)了Ordered接口的processor,對它們進行排序后執(zhí)行processor中的邏輯。List orderedPostProcessors = new ArrayList(orderedPostProcessorNames.size());for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// 最后執(zhí)行,沒有順序要求的processorList 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();}//調(diào)用processors中的postProcessBeanFactory方法private static void invokeBeanFactoryPostProcessors(Collection 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();}}
小結(jié)
整個執(zhí)行流程的源碼還是比較清晰并且簡單的。重點提下下面兩個點:
看源碼得知,String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);獲取所有實現(xiàn)了BeanFactoryPostProcessor的Bean Name, 前提所有的Bean都要被注冊到BeanDefinitionRegistry, 通過添加@Component, @Service等注解,可以將對應(yīng)的Bean定義信息注冊到BeanFactory中,方便后面實例化Bean。 那么它是在什么地方注冊的呢?可以看下ConfigurationClassPostProcessor類,它實現(xiàn)了BeanDefinitionRegistryPostProcessor,會掃描所有@Component, @Service等注解,將對應(yīng)的Bean Definition注冊到BeanFactory中。
我們可以通過實現(xiàn)PriorityOrdered, Ordered接口,控制BeanFactoryProcessor的執(zhí)行順序,, 優(yōu)先執(zhí)行實現(xiàn)了PriorityOrdered接口,其次是Ordered,最后是沒有實現(xiàn)任何排序接口的processor。
內(nèi)置的BeanFactoryPostProcessor
Spring內(nèi)置了一個比較重要的BeanFactoryPostProcessor是PlaceholderConfigurerSupport, 實現(xiàn)從配置文件中獲取屬性。
作者:JAVA旭陽鏈接:https://juejin.cn/post/7107561134860959757
“做程序員,圈子和學習最重要”因為有有了圈子可以讓你少走彎路,擴寬人脈,擴展思路,學習他人的一些經(jīng)驗及學習方法!同時在這分享一下是一直以來整理的Java后端進階筆記文檔和學習資料免費分享給大家!需要資料的朋友私信我扣【888】