Spring经典扩展接口应用:BeanFactoryPostProcessor

目录

一、BeanFactoryPostProcessor基本知识总结

二、BeanFactoryPostProcessor在框架中的使用

三、扩展应用代码举例分析

扩展一:通过实现BeanFactoryPostProcessor接口修改Bean定义

扩展二:通过实现BeanFactoryPostProcessor接口注册新的Bean定义

扩展三:通过实现BeanFactoryPostProcessor接口修改Bean定义

思考1:自定义BeanFactoryProcessor需要加@Component等注解的原因

思考2:如何控制BeanFactoryProcessor的执行顺序

四、业务使用时的使用建议及注意事项

五、源码分析

扫描二维码关注公众号,回复: 16772260 查看本文章

(一)接口定义分析

(二)执行流程分析

参考文章链接


一、BeanFactoryPostProcessor基本知识总结

BeanFactoryPostProcessor是Spring框架中的一个重要接口,用于在BeanFactory加载Bean定义之后、实例化Bean之前对BeanFactory进行自定义修改和扩展它允许开发人员在Spring容器加载配置文件并创建Bean实例之前对Bean定义进行操作,例如修改属性值、添加额外的元数据等。

BeanFactoryPostProcessor接口定义了一个方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
throws BeansException;

在应用程序启动时,Spring容器会自动检测并调用所有实现了BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法。开发人员可以利用这个方法来实现自定义的逻辑,对BeanFactory进行修改和扩展。

通过实现BeanFactoryPostProcessor接口,可以实现以下功能:

  1. 修改Bean定义:可以在BeanFactory加载Bean定义后,对Bean定义进行修改。例如,可以根据某些条件动态修改Bean的属性值、更改Bean的作用域等。
  2. 注册新的Bean定义:可以在BeanFactory加载Bean定义后,向BeanFactory中注册新的Bean定义。这样,可以动态地向Spring容器中添加新的Bean定义,从而实现动态扩展。
  3. 添加自定义元数据:可以向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定义后,自动向容器中注册一个名为additionalBeanAdditionalBean实例。首先,创建一个实现了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构建了一个AdditionalBeanBeanDefinition实例,并使用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",表示成功注册并获取到了名为additionalBeanAdditionalBean实例。

在这个案例中,通过实现postProcessBeanDefinitionRegistry方法,在BeanFactory加载Bean定义后向BeanFactory中注册了一个新的Bean定义。注册的Bean定义使用BeanDefinitionBuilder来创建,并通过BeanDefinitionRegistryregisterBeanDefinition方法进行注册。

然后,通过将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的执行顺序

可以通过实现PriorityOrderedOrdered接口,控制BeanFactoryProcessor的执行顺序, 优先执行实现了PriorityOrdered接口,其次是Ordered,最后是没有实现任何排序接口的processor。

四、业务使用时的使用建议及注意事项

当使用BeanFactoryPostProcessor接口来实现自定义功能时,以下是一些使用注意事项和建议:

  1. BeanFactoryPostProcessor在BeanFactory加载Bean定义后执行,但在Bean实例化之前执行。这意味着,BeanFactoryPostProcessor可以修改Bean定义的属性,但无法修改Bean实例的状态。如果需要在Bean实例化后修改Bean的属性或执行其他操作,可以考虑使用BeanPostProcessor接口。
  2. 避免在BeanFactoryPostProcessor中创建循环依赖关系。BeanFactoryPostProcessor的执行顺序是在Bean实例化之前,因此如果在BeanFactoryPostProcessor中创建新的Bean实例,且该实例依赖于其他Bean,可能会导致循环依赖的问题。
  3. 尽量避免在BeanFactoryPostProcessor中引入复杂的业务逻辑。BeanFactoryPostProcessor的主要目的是对BeanFactory进行修改和扩展,而不是执行复杂的业务逻辑。如果需要执行复杂的业务逻辑,可以考虑使用其他适合的组件,如BeanPostProcessor或自定义的Service类。
  4. 注意BeanFactoryPostProcessor的执行顺序。如果有多个BeanFactoryPostProcessor实现类,它们的执行顺序可能对结果产生影响。可以使用@Order注解或实现Ordered接口来指定执行顺序,或者使用Ordered接口的优先级常量(如Ordered.HIGHEST_PRECEDENCE)。
  5. 谨慎使用BeanFactoryPostProcessor注册新的Bean定义。注册新的Bean定义可能会导致应用程序的复杂性增加,因此应谨慎使用。确保新注册的Bean定义符合应用程序的需求,并避免过度依赖动态注册的Bean。
  6. 在使用BeanFactoryPostProcessor时,建议遵循单一职责原则。每个BeanFactoryPostProcessor类应该专注于一个特定的任务或功能,以保持代码的清晰性和可维护性。
  7. 注意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方法,该方法的前面部分逻辑主要是处理BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry方法,也就是想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();
		}
	}

参考文章链接

  1. Baeldung: "Introduction to BeanFactoryPostProcessor in Spring" - 这篇文章提供了对BeanFactoryPostProcessor的简介,解释了它的作用、使用方式以及示例代码。你可以在Baeldung网站上找到这篇文章。
  2. DZone: "Understanding the Role of BeanFactoryPostProcessor in Spring Framework" - 这篇文章详细解释了BeanFactoryPostProcessor的作用和用途,并提供了示例代码来说明如何使用它。你可以在DZone网站上找到这篇文章。
  3. Spring Framework Reference Documentation - Spring官方文档提供了关于BeanFactoryPostProcessor的详细解释和用法说明。你可以访问Spring官方网站,并查找官方文档中关于BeanFactoryPostProcessor的部分。
  4. Baeldung: "Spring BeanFactoryPostProcessor Tutorial" - 这篇教程提供了一个完整的示例,演示了如何使用BeanFactoryPostProcessor来修改Bean定义和注册新的Bean定义。你可以在Baeldung网站上找到这篇教程。
  5. 一文吃透Spring Boot扩展之BeanFactoryPostProcessor - 掘金

猜你喜欢

转载自blog.csdn.net/xiaofeng10330111/article/details/130191640