目录
一、BeanFactoryPostProcessor基本知识总结
二、BeanFactoryPostProcessor在框架中的使用
扩展一:通过实现BeanFactoryPostProcessor接口修改Bean定义
扩展二:通过实现BeanFactoryPostProcessor接口注册新的Bean定义
扩展三:通过实现BeanFactoryPostProcessor接口修改Bean定义
思考1:自定义BeanFactoryProcessor需要加@Component等注解的原因
思考2:如何控制BeanFactoryProcessor的执行顺序
一、BeanFactoryPostProcessor基本知识总结
BeanFactoryPostProcessor是Spring框架中的一个重要接口,用于在BeanFactory加载Bean定义之后、实例化Bean之前对BeanFactory进行自定义修改和扩展。它允许开发人员在Spring容器加载配置文件并创建Bean实例之前对Bean定义进行操作,例如修改属性值、添加额外的元数据等。
BeanFactoryPostProcessor接口定义了一个方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
在应用程序启动时,Spring容器会自动检测并调用所有实现了BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法。开发人员可以利用这个方法来实现自定义的逻辑,对BeanFactory进行修改和扩展。
通过实现BeanFactoryPostProcessor接口,可以实现以下功能:
- 修改Bean定义:可以在BeanFactory加载Bean定义后,对Bean定义进行修改。例如,可以根据某些条件动态修改Bean的属性值、更改Bean的作用域等。
- 注册新的Bean定义:可以在BeanFactory加载Bean定义后,向BeanFactory中注册新的Bean定义。这样,可以动态地向Spring容器中添加新的Bean定义,从而实现动态扩展。
- 添加自定义元数据:可以向Bean定义中添加自定义的元数据,以供后续的处理器使用。这样,其他处理器或组件可以根据这些元数据进行相应的处理。
需要注意的是,BeanFactoryPostProcessor的实现类必须在Spring容器启动之前被注册到容器中,以确保在容器加载Bean定义时能够被正确调用。
总结起来,BeanFactoryPostProcessor是Spring框架中用于对BeanFactory进行自定义修改和扩展的接口。通过实现该接口,可以在BeanFactory加载Bean定义后、实例化Bean之前对BeanFactory进行修改,从而实现一些高级的自定义逻辑和功能扩展。
二、BeanFactoryPostProcessor在框架中的使用
BeanFactoryPostProcessor在Spring框架中也有大量的使用案例。其中,最经典的案例莫过于PropertyPlaceholderConfigurer,它是Spring框架中的一个BeanFactoryPostProcessor实现类,可以在容器加载时,动态替换配置文件中的占位符,将占位符替换为真正的属性值。
回到之前提到的,BeanFactoryPostProcessor接口中主要定义的方法
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
可以看到,这个方法接收的参数是ConfigurableListableBeanFactory类型,这是Spring容器的核心接口,也是BeanFactory接口的子接口。ConfigurableListableBeanFactory可以通过继承自BeanFactory的方法获取容器中所有的Bean,并支持像BeanPostProcessor这样的接口,从而增强bean的扩展能力。
查看源码如下所示:
public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
implements BeanFactoryPostProcessor, EnvironmentAware, EmbeddedValueResolverAware {
/** Default placeholder prefix: "${" */
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
/** Default placeholder suffix: "}" */
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
// 用来替换占位符的属性解析器
private volatile PropertySourcesPlaceholderConfigurer pp;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
processProperties(beanFactory, pp.getAppliedPropertySources());
this.pp = null;
}
...
}
可以看到,PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor接口,所以它的postProcessBeanFactory方法会在应用上下文加载时调用。
在该方法中,PropertyPlaceholderConfigurer会调用父类PlaceholderConfigurerSupport中的processProperties方法来替换属性占位符。
processProperties方法中会依次遍历容器中的BeanDefinition,找到并处理所有Key为"props"的PropertyPlaceholderConfigurer类的Bean并将其组成的数组中的每个实例都加入到PropertySourcesPlaceholderConfigurer的属性源列表中。
接下来,PropertyPlaceholderConfigurer会调用processProperties方法,并返回值pp,然后在方法的最后将它置为空。这样在下一次调用的时候,又会重新创建一个新的PropertySourcesPlaceholderConfigurer实例。
总体来说,通过实现BeanFactoryPostProcessor接口,可以在Spring容器创建Bean之前对Bean定义进行修改、文件占位符变量的替换等操作。而PropertyPlaceholderConfigurer作为一个经典的BeanFactoryPostProcessor实现类,可以随时动态替换配置文件中的占位符,并将其应用到Spring容器中的所有Bean中。
除了PropertyPlaceholderConfigurer,Spring框架中还有大量的BeanFactoryPostProcessor实现类,比如CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor等等,它们都广泛应用于Spring中各种各样的场景中。
三、扩展应用代码举例分析
扩展一:通过实现BeanFactoryPostProcessor接口修改Bean定义
该扩展的使用本意是指:当需要在Spring容器加载Bean定义后对Bean的定义进行修改时,可以使用BeanFactoryPostProcessor接口来实现。下面是一个简单的案例分析。
假设有一个名为MyTestMsgBean的Bean类:
package org.zyf.javabasic.springextend.bfppext;
/**
* @author yanfengzhang
* @description 演示如何使用BeanFactoryPostProcessor来修改Bean的定义
* @date 2023/5/17 22:57
*/
public class MyTestMsgBean {
private String message;
public void setMessage(String message) {
this.message = message;
}
public void displayMessage() {
System.out.println("MyTestMsgBean Message: " + message);
}
}
现在,我们希望在Spring容器加载Bean定义后,自动将MyTestMsgBean的message属性值修改为特定的默认值。
首先创建自定义类MyBeanFactoryPostProcessorForUpdateBean实现BeanFactoryPostProcessor接口如下:
package org.zyf.javabasic.springextend.bfppext;
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;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:00
*/
@Component
public class MyBeanFactoryPostProcessorForUpdateBean implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("myTestMsgBean");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.add("message", "Hello, World!");
}
}
在上述代码中,MyBeanFactoryPostProcessorForUpdateBean类实现了BeanFactoryPostProcessor接口,并重写了postProcessBeanFactory方法。在该方法中,我们通过configurableListableBeanFactory.getBeanDefinition("myTestMsgBean")获取MyTestMsgBean的BeanDefinition,然后使用MutablePropertyValues来修改message属性的值。
接下来,将MyTestMsgBean和MyBeanFactoryPostProcessorForUpdateBean都配置到Spring的配置文件中(zyf_application_context.xml):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myTestMsgBean" class="org.zyf.javabasic.springextend.bfppext.MyTestMsgBean">
<property name="message" value="Original Message"/>
</bean>
<bean class="org.zyf.javabasic.springextend.bfppext.MyBeanFactoryPostProcessorForUpdateBean"/>
</beans>
在上述配置中,首先定义了一个名为myTestMsgBean的MyTestMsgBean实例,并给其message属性设置了一个初始值,并将MyBeanFactoryPostProcessorForUpdateBean注册到Spring容器中。
当Spring容器启动时,它会首先加载配置文件并解析Bean定义,然后自动检测到MyBeanFactoryPostProcessorForUpdateBean类实现了BeanFactoryPostProcessor接口,并调用其postProcessBeanFactory方法。在该方法中,我们修改了MyTestMsgBean的message属性值为"Hello, World!"。
最后,可以通过获取MyTestMsgBean的实例并调用其方法来验证修改是否生效:
package org.zyf.javabasic.springextend.bfppext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:07
*/
public class MyBeanFactoryPostProcessorForUpdateBeanTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("zyf_application_context.xml");
MyTestMsgBean myBean = context.getBean(MyTestMsgBean.class);
myBean.displayMessage();
}
}
运行上述代码,输出将是:"MyTestMsgBean Message: Hello, World!",而不是初始值"MyTestMsgBean Message: Original Message"。这表明我们成功地使用`MyBeanFactoryPostProcessorForUpdateBean`修改了`MyTestMsgBean`的定义,将其属性值修改为了我们所期望的默认值。
这个案例演示了如何使用`BeanFactoryPostProcessor`接口来修改Bean的定义。通过实现该接口并在`postProcessBeanFactory`方法中对Bean的定义进行修改,我们可以轻松地实现自定义的逻辑和扩展,以满足特定的需求。
扩展二:通过实现BeanFactoryPostProcessor接口注册新的Bean定义
该扩展的使用本意是指:当需要在BeanFactory加载Bean定义后,向BeanFactory中注册新的Bean定义时,可以使用BeanFactoryPostProcessor接口来实现。下面是一个完整的案例,演示如何使用BeanFactoryPostProcessor注册新的Bean定义。
假设我们有一个名为AdditionalBean的Bean类:
package org.zyf.javabasic.springextend.bfppext;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:34
*/
public class AdditionalBean {
public void displayMessage() {
System.out.println("Additional Bean");
}
}
现在,我们希望在Spring容器加载Bean定义后,自动向容器中注册一个名为additionalBean的AdditionalBean实例。首先,创建一个实现了BeanFactoryPostProcessor接口的自定义类MyBeanFactoryPostProcessorForNewDefinRegi:
package org.zyf.javabasic.springextend.bfppext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:36
*/
@Component
public class MyBeanFactoryPostProcessorForNewDefinRegi implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(AdditionalBean.class).getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition("additionalBean", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
// 这里留空
}
}
MyBeanFactoryPostProcessorForNewDefinRegi实现了BeanDefinitionRegistryPostProcessor接口,并重写了postProcessBeanDefinitionRegistry方法。在该方法中,我们使用BeanDefinitionBuilder构建了一个AdditionalBean的BeanDefinition实例,并使用registry.registerBeanDefinition方法将其注册到BeanDefinitionRegistry中,其中第一个参数是Bean的名称,第二个参数是BeanDefinition实例。
接下来,将MyBeanFactoryPostProcessorForNewDefinRegi配置到其中:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myTestMsgBean" class="org.zyf.javabasic.springextend.bfppext.MyTestMsgBean">
<property name="message" value="Original Message"/>
</bean>
<bean class="org.zyf.javabasic.springextend.bfppext.MyBeanFactoryPostProcessorForUpdateBean"/>
<bean class="org.zyf.javabasic.springextend.bfppext.MyBeanFactoryPostProcessorForNewDefinRegi"/>
</beans>
在上述配置中,我们只需要将MyBeanFactoryPostProcessorForNewDefinRegi注册到Spring容器中。最后,创建一个测试类来验证新的Bean定义是否生效:
package org.zyf.javabasic.springextend.bfppext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:53
*/
public class MyBeanFactoryPostProcessorForNewDefinRegiTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("zyf_application_context.xml");
AdditionalBean additionalBean = context.getBean(AdditionalBean.class);
additionalBean.displayMessage();
}
}
运行上述代码,输出将是:"Additional Bean",表示成功注册并获取到了名为additionalBean的AdditionalBean实例。
在这个案例中,通过实现postProcessBeanDefinitionRegistry方法,在BeanFactory加载Bean定义后向BeanFactory中注册了一个新的Bean定义。注册的Bean定义使用BeanDefinitionBuilder来创建,并通过BeanDefinitionRegistry的registerBeanDefinition方法进行注册。
然后,通过将MyBeanFactoryPostProcessorForNewDefinRegi配置到Spring的配置文件中,并使用ApplicationContext来获取注册的Bean实例,我们可以验证新的Bean定义是否成功注册到了Spring容器中。
这个案例展示了如何使用BeanFactoryPostProcessor接口来实现注册新的Bean定义。这种方法使得我们可以在BeanFactory加载Bean定义后,动态地向Spring容器中添加新的Bean定义,从而实现灵活的扩展和配置。
扩展三:通过实现BeanFactoryPostProcessor接口修改Bean定义
该扩展的使用本意是指:当需要向Bean定义中添加自定义的元数据,以供后续处理器使用时,可以使用BeanFactoryPostProcessor接口来实现。下面是一个完整的案例演示添加自定义元数据。
假设我们有一个名为MyTestMsgBean的Bean类,如之前的代码,现在,我们希望在Bean定义中添加一个自定义的元数据,例如customData,以供其他处理器或组件使用。
首先,创建自定义类MyBeanFactoryPostProcessorForDefineMata实现对应接口:
package org.zyf.javabasic.springextend.bfppext;
import org.springframework.beans.BeansException;
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.stereotype.Component;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:12
*/
@Component
public class MyBeanFactoryPostProcessorForDefineMata implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition("myTestMsgBean");
beanDefinition.setAttribute("customData", "This is custom data");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
// 这里留空
}
}
在上述代码中,MyBeanFactoryPostProcessorForDefineMata类实现了BeanDefinitionRegistryPostProcessor接口,并重写了postProcessBeanDefinitionRegistry方法。在该方法中,我们获取了名为myTestMsgBean的Bean定义,并使用setAttribute方法向Bean定义中添加了自定义的元数据customData。
接下来将MyBeanFactoryPostProcessorForDefineMata配置到其中:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myTestMsgBean" class="org.zyf.javabasic.springextend.bfppext.MyTestMsgBean">
<property name="message" value="Original Message"/>
</bean>
<bean class="org.zyf.javabasic.springextend.bfppext.MyBeanFactoryPostProcessorForUpdateBean"/>
<bean class="org.zyf.javabasic.springextend.bfppext.MyBeanFactoryPostProcessorForNewDefinRegi"/>
<bean class="org.zyf.javabasic.springextend.bfppext.MyBeanFactoryPostProcessorForDefineMata"/>
</beans>
在上述配置中,我们只需要将MyBeanFactoryPostProcessorForDefineMata注册到Spring容器中。最后,创建一个测试类来获取Bean定义的元数据并验证是否成功添加:
package org.zyf.javabasic.springextend.bfppext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author yanfengzhang
* @description
* @date 2023/5/17 23:15
*/
public class MyBeanFactoryPostProcessorForDefineMataTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("zyf_application_context.xml");
ConfigurableApplicationContext configurableContext = (ConfigurableApplicationContext) context;
BeanDefinition beanDefinition = configurableContext.getBeanFactory().getBeanDefinition("myTestMsgBean");
Object customData = beanDefinition.getAttribute("customData");
System.out.println("Custom Data: " + customData);
}
}
运行上述代码,输出将是:"Custom Data: This is custom data",表示成功地向Bean定义中添加了自定义的元数据。这个案例演示了如何使用BeanFactoryPostProcessor接口来添加自定义的元数据到Bean定义中。通过实现BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,我们可以在BeanFactory加载Bean定义后,向Bean定义中添加自定义的元数据。请注意,添加的元数据可以在后续的处理器或组件中使用,以根据元数据进行相应的处理逻辑。
思考1:自定义BeanFactoryProcessor需要加@Component
等注解的原因
看源码得知:
String[] postProcessorNames = beanFactory
.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
获取所有实现了BeanFactoryPostProcessor的BeanName, 前提所有的Bean都要被注册到BeanDefinitionRegistry
, 通过添加@Component
, @Service
等注解,可以将对应的Bean定义信息注册到BeanFactory中,方便后面实例化Bean。 那么它是在什么地方注册的呢?
可以看下ConfigurationClassPostProcessor
类,它实现了BeanDefinitionRegistryPostProcessor
,会扫描所有@Component
, @Service
等注解,将对应的Bean Definition注册到BeanFactory中。
思考2:如何控制BeanFactoryProcessor
的执行顺序
可以通过实现PriorityOrdered
, Ordered
接口,控制BeanFactoryProcessor
的执行顺序, 优先执行实现了PriorityOrdered
接口,其次是Ordered
,最后是没有实现任何排序接口的processor。
四、业务使用时的使用建议及注意事项
当使用BeanFactoryPostProcessor接口来实现自定义功能时,以下是一些使用注意事项和建议:
- BeanFactoryPostProcessor在BeanFactory加载Bean定义后执行,但在Bean实例化之前执行。这意味着,BeanFactoryPostProcessor可以修改Bean定义的属性,但无法修改Bean实例的状态。如果需要在Bean实例化后修改Bean的属性或执行其他操作,可以考虑使用BeanPostProcessor接口。
- 避免在BeanFactoryPostProcessor中创建循环依赖关系。BeanFactoryPostProcessor的执行顺序是在Bean实例化之前,因此如果在BeanFactoryPostProcessor中创建新的Bean实例,且该实例依赖于其他Bean,可能会导致循环依赖的问题。
- 尽量避免在BeanFactoryPostProcessor中引入复杂的业务逻辑。BeanFactoryPostProcessor的主要目的是对BeanFactory进行修改和扩展,而不是执行复杂的业务逻辑。如果需要执行复杂的业务逻辑,可以考虑使用其他适合的组件,如BeanPostProcessor或自定义的Service类。
- 注意BeanFactoryPostProcessor的执行顺序。如果有多个BeanFactoryPostProcessor实现类,它们的执行顺序可能对结果产生影响。可以使用@Order注解或实现Ordered接口来指定执行顺序,或者使用Ordered接口的优先级常量(如Ordered.HIGHEST_PRECEDENCE)。
- 谨慎使用BeanFactoryPostProcessor注册新的Bean定义。注册新的Bean定义可能会导致应用程序的复杂性增加,因此应谨慎使用。确保新注册的Bean定义符合应用程序的需求,并避免过度依赖动态注册的Bean。
- 在使用BeanFactoryPostProcessor时,建议遵循单一职责原则。每个BeanFactoryPostProcessor类应该专注于一个特定的任务或功能,以保持代码的清晰性和可维护性。
- 注意BeanFactoryPostProcessor的生命周期。BeanFactoryPostProcessor实现类是在应用程序上下文的启动阶段执行的,因此需要确保它们的执行时间较短,以避免影响应用程序的启动性能。通过遵循这些注意事项和建议,可以更好地使用BeanFactoryPostProcessor接口实现所需的功能,并确保应用程序的正常运行和可维护性。
五、源码分析
(一)接口定义分析
/**
* 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.
*
* <p>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.
*
* <p>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.
*
* <h3>Registration</h3>
* <p>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}.
*
* <h3>Ordering</h3>
* <p>{@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<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
.......... 该部分是处理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();
}
}
参考文章链接
- Baeldung: "Introduction to BeanFactoryPostProcessor in Spring" - 这篇文章提供了对BeanFactoryPostProcessor的简介,解释了它的作用、使用方式以及示例代码。你可以在Baeldung网站上找到这篇文章。
- DZone: "Understanding the Role of BeanFactoryPostProcessor in Spring Framework" - 这篇文章详细解释了BeanFactoryPostProcessor的作用和用途,并提供了示例代码来说明如何使用它。你可以在DZone网站上找到这篇文章。
- Spring Framework Reference Documentation - Spring官方文档提供了关于BeanFactoryPostProcessor的详细解释和用法说明。你可以访问Spring官方网站,并查找官方文档中关于BeanFactoryPostProcessor的部分。
- Baeldung: "Spring BeanFactoryPostProcessor Tutorial" - 这篇教程提供了一个完整的示例,演示了如何使用BeanFactoryPostProcessor来修改Bean定义和注册新的Bean定义。你可以在Baeldung网站上找到这篇教程。
- 一文吃透Spring Boot扩展之BeanFactoryPostProcessor - 掘金