Spring中BeanFactoryPostProcessor接口 -【Spring底层原理】

1,266 阅读3分钟

blog57

一、概述

BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入,这些都是如何实现的呢,本文将一探究竟。

区分:

  • BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
  • BeanFactoryPostProcessor:beanFactory后置处理器,在beanFactory标准初始化之后调用,此时所有的bean定义已经保存加载到beanFactory中,但bean的实例还未创建,此时可以对bean的属性进行修改拓展

二、实例分析

// 启动类
@Test
public void TestMain() {
    // 创建IOC容器
    new AnnotationConfigApplicationContext(AppConfig.class);
}

// 待注入的bean
public class User {
    public User(){
        System.out.println("user create");
    }
}

// 配置类
@ComponentScan("config")
@Configuration
public class AppConfig {
    @Bean
    public User user(){
        return new User();
    }
}

// BeanFactoryPostProcessor实现类
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor#postProcessBeanFactory");
        int count = configurableListableBeanFactory.getBeanDefinitionCount();
        String[] names = configurableListableBeanFactory.getBeanDefinitionNames();
        System.out.println("当前BeanFactory中有" + count + "个Bean");
        System.out.println(Arrays.asList(names));
    }
}

运行启动类,可以看到,通过获取到容器中的组件,发现在bean创建之前,就执行了MyBeanFactoryPostProcessor的postProcessBeanFactory方法,由此可以看出,在bean的实例还未创建的时候,也就是初始化之前,就会调用BeanFactoryPostProcessor,因此,可以在这里进行功能的拓展,修改bean的属性。

三、源码分析

具体是如何调用的,我们通过源码进行分析,使用Debug的方式来一步一步查看方法调用链,在postProcessBeanFactory方法的位置打上断点,Debug运行启动类:

可以看到,进入了refresh()方法的invokeBeanFactoryPostProcessors方法,也就是说,在invokeBeanFactoryPostProcessors方法中就执行了beanFactory的后置处理器方法。

image-20210317192535369

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        ......
        // 在这个方法执行了beanFactory的后置处理器
        this.invokeBeanFactoryPostProcessors(beanFactory);
        ......
    }
}

进入到下一个方法,到invokeBeanFactoryPostProcessors#invokeBeanFactoryPostProcessors方法,

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    ......
    sortPostProcessors(regularPostProcessors, beanFactory);
    // 先执行实现了PriorityOrdered接口的PostProcessor(实现优先级接口的)
    invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(registryProcessors.size());
    Iterator var21 = registryProcessors.iterator();

    while(var21.hasNext()) {
        String postProcessorName = (String)var21.next();
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }

    sortPostProcessors(orderedPostProcessors, beanFactory);
    // 再执行实现了Ordered接口的PostProcessor
    invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(currentRegistryProcessors.size());
    Iterator var24 = currentRegistryProcessors.iterator();

    while(var24.hasNext()) {
        ppName = (String)var24.next();
        // 从bean工厂中获取BeanFactoryPostProcessor,得到每一个PostProcessor的名字
        nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }

    // 执行beanFactory后置处理器(最后执行普通接口的PostProcessor)
    invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    beanFactory.clearMetadataCache();
}

可以看到,在这个方法里面,是调用最下面的invokeBeanFactoryPostProcessors方法执行beanFactory后置处理器的,提出疑问:

我们是如何找到PostProcessor并执行他们的方法呢?

【1】获取PostProcessor

上面代码分别执行了三种接口的BeanFactoryPostProcessors,在执行之前,会对PostProcessor进行处理,如下,将三种PostProcessor分开放置:

  • priorityOrderedPostProcessors:放置有优先级排序的接口
  • orderedPostProcessorNames:放置有排序的PostProcessorNames
  • nonOrderedPostProcessorNames:放置普通的PostProcessorNames
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
 	......
    for(int var10 = 0; var10 < var9; ++var10) {
        ppName = var8[var10];
        // 将有优先级排序接口的放到priorityOrderedPostProcessors
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
            priorityOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
            // 将有排序接口的放到orderedPostProcessorNames
        } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        } else {
            // 将普通接口的放到nonOrderedPostProcessorNames
            nonOrderedPostProcessorNames.add(ppName);
        }
    }
    ......
}

这里百便获取到了相应的PostProcessor,有PriorityOrdered接口的,有Ordered接口的,也有普通接口的 ,之后,进行遍历,我们实现的是普通接口的,从bean工厂中获取BeanFactoryPostProcessor,得到每一个PostProcessor的名字

【2】遍历执行PostProcessor

private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    Iterator var2 = postProcessors.iterator();

    while(var2.hasNext()) {
        BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
        StartupStep var10000 = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process");
        postProcessor.getClass();
        StartupStep postProcessBeanFactory = var10000.tag("postProcessor", postProcessor::toString);
        postProcessor.postProcessBeanFactory(beanFactory);
        postProcessBeanFactory.end();
    }
}

遍历出每个PostProcessor,回调每一个的postProcessBeanFactory方法。

四、总结

  1. refresh():IOC容器创建对象
  2. invokeBeanFactoryPostProcessors():执行BeanFactoryPostProcessors,即beanFactory的后置处理器
    1. 直接在BeanFactory中找到所有类型是BeanFactoryPostProcessors的组件,并执行他们的方法
    2. 通过源码可以看到,是在初始化其他组件(finishBeanFactoryInitialization)之前执行的