美文网首页
Spring源码解析(十六)-BeanFactoryPostPr

Spring源码解析(十六)-BeanFactoryPostPr

作者: 秋水畏寒 | 来源:发表于2020-06-06 16:19 被阅读0次

Spring版本

5.2.5.RELEASE

参考

《芋道源码》

源码解读

我们知道,BeanPostProcessor是用来改变bean实例的。同样在 Spring 容器启动阶段,Spring 也提供了一种容器扩展机制:BeanFactoryPostProcessor,该机制作用于容器启动阶段,允许我们在容器实例化 Bean 之前对注册到该容器的 BeanDefinition 做出修改。

@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;

}

从源码注释可以看出,该接口是在standard initialization之后修改容器上下文的内部bean factory,这时候所有的bean definition已经被加载,但是还没初始化任何一个bean。下面通过具体例子来清晰认识一下。

Demo

Student

public class Student {

    private String id;

    private String name;

    private String desc;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

MyBeanFactoryPostProcessor

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        System.out.println("call MyBeanFactoryPostProcessor#postProcessBeanFactory");
        BeanDefinition student = beanFactory.getBeanDefinition("student");
        student.getPropertyValues().add("name", "name set by custom BeanFactoryPostProcessor");
    }
}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="myBeanFactoryPostProcessor" class="com.kungyu.custom.element.MyBeanFactoryPostProcessor"/>
    <bean id="student" class="com.kungyu.custom.element.Student">
        <property name="name" value="name"/>
        <property name="id" value="id"/>
    </bean>
</bean>

测试

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
  }
}

结果

BeanFactoryPostProcessor
可以看到,在spring.xml文件中设置的name属性已经被覆盖。

BeanPostProcessor类似,当我们自定义多个有序的BeanFactoryPostProcessor的时候,需要实现Ordered接口重写getOrder方法定义执行顺序。

思考

回头看前面对于BeanDefinition的解析文章,发现并不像BeanPostProcessor那样,在bean实例化过程中调用了BeanPostProcessor进行增强处理,那么,BeanFactoryPostProcessor到底是在哪里对BeanDefinition进行了处理呢?

怀着疑问对心情,开始debug,断点位于MyBeanFactoryPostProcessor#postProcessBeanFactory中,发现调用栈如下:

postProcessBeanFactory调用栈
可以看到,在ClassPathXmlApplicationContext初始化代码中,调用了invokeBeanFactoryPostProcessors方法:
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

这里通过getBeanFactoryPostProcessors拿到了我们自定义的BeanFactoryPostProcessor。那么,BeanDefinition是在哪里加载的呢?查看processBeanDefinition调用栈如下:

processBeanDefinition调用栈
可以看到也是在ClassPathXmlApplicationContext初始化中调用的,并且调用的方法obtainFreshBeanFactory是在invokeBeanFactoryPostProcessors之前调用的。

总结

一般情况下,我们不会去自定义BeanFactoryPostProcessor,而是使用spring提供的BeanFactoryPostProcessor。常用的BeanFactoryPostProcessor有以下俩个:

相关文章

网友评论

      本文标题:Spring源码解析(十六)-BeanFactoryPostPr

      本文链接:https://www.haomeiwen.com/subject/zilnahtx.html