逐行阅读Spring5.X源码(五) 初探BeanFactoryPostProcessor后置处理器,难,特别难。

时间:2022-07-24
本文章向大家介绍逐行阅读Spring5.X源码(五) 初探BeanFactoryPostProcessor后置处理器,难,特别难。,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前几篇博文我们详细讲解了BeanDefinition的源码,我们知道spring扫描符合规则的业务类后会将业务类封装成BeanDefinition保存在IOC容器中,那么,spring容器启动过程中是在哪里扫描的呢? 答案是在BeanFactoryPostProcessor后置处理器中完成扫描功能,不仅仅是类扫描,BeanFactoryPostProcessor能完成更丰富的功能,比如bean拦截处理、spring扩展开发都离不开它。从本篇文章开始,笔者将向大家详细阐述BeanFactoryPostProcessor。

引出

BeanFactoryPostProcessor分两种,一种是spring内置,一种由程序员提供。我们首先通过注解的方式启动spring:

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(Config.class);
        context.refresh();

context.refresh()完成了spring的启动过程,类扫描也是在这个方法中完成的,这个方法的实现是在AnnotationConfigApplicationContext 父类AbstractApplicationContext方法中完成的,单击该行代码跳转到具体的实现,找到下面这行源码:

     // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);

这样代码的意思是,先执行已经注册到bean工厂中的所有内置BeanFactoryPostProcessor,再执行程序员提供的BeanFactoryPostProcessor。那么什么是BeanFactoryPostProcessor ?

BeanFactoryPostProcessor

BeanFactoryPostProcessor是bean工厂的后置处理器,干预bean工厂的工作流程。那么什么又是bean工厂咩?AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();这行代码首先会执行无参构造函数,学过java的读者都知道,无参构造函数在调用前先调用父类的构造函数,AnnotationConfigApplicationContext 的父类是GenericApplicationContext

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

我们看下GenericApplicationContext无参构造函数:

private final DefaultListableBeanFactory beanFactory;
          ......省略......
public GenericApplicationContext() {
        //实例化bean工厂
        this.beanFactory = new DefaultListableBeanFactory();
    }

DefaultListableBeanFactory(详情参考上一篇博文)就是bean工厂,在BeanDefinition我们讲过spring生成的BeanDefinition会保存在一个map当中,这个map就是保存在DefaultListableBeanFactory当中:

    //DefaultListableBeanFactory源码中的beanDefinitionMap 变量,用于保存BeanDefinition
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

BeanFactoryPostProcessor 是一个接口,它只定义了一个方法postProcessBeanFactory,spring启动过程中会自动回调BeanFactoryPostProcessor 的实现类的postProcessBeanFactory方法,这个方法有一个ConfigurableListableBeanFactory 的类型参数beanFactory,也就是说我们可以在这个postProcessBeanFactory方法里操作bean工厂,bean工厂何许人也,那岂不是肆意妄为!相当于我们控制住了敌人的兵工厂。这也是spring扩展开发的根本,专业讲是Spring初始化bean时对外暴露的扩展点。

@FunctionalInterface
public interface BeanFactoryPostProcessor {
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

Spring IoC容器允许BeanFactoryPostProcessor在容器实例化任何bean之前读取bean的定义(配置元数据),并可以修改它。同时可以定义多个BeanFactoryPostProcessor,通过设置'order'属性来确定各个BeanFactoryPostProcessor执行顺序。注册一个BeanFactoryPostProcessor实例需要定义一个Java类来实现BeanFactoryPostProcessor接口,并重写该接口的postProcessorBeanFactory方法,spring启动过程中会自动调用我们的后置处理器:

@Component
public class CZZBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("自己定义的后置处理器,在这里我可以拿到bean工厂");
    }
}
————————————————————————————————————————
public class SpringTest {
    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);
        //加载或者刷新当前的配置信息
        context.refresh();
    }
}

自定义后置处理器

BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor有个子接口BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    /**
     * Modify the application context's internal bean definition registry after its
     * standard initialization. All regular bean definitions will have been loaded,
     * but no beans will have been instantiated yet. This allows for adding further
     * bean definitions before the next post-processing phase kicks in.
     * @param registry the bean definition registry used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

该接口只定义一个postProcessBeanDefinitionRegistry方法,且传入的参数类型是BeanDefinitionRegistry,如果你读过上一篇bean工厂的博文就该知道这是遵循了7大软件设计原则中的迪米特法则。怎么讲?spring真正的bean工厂是DefaultListableBeanFactory,而ConfigurableListableBeanFactoryBeanDefinitionRegistry都是DefaultListableBeanFactory的上层接口,缩小了传入参数可访问的方法,换句话讲降低了你的权限,如果spring回调你的方法给你传入一个DefaultListableBeanFactory类型的参数,那么你将得到整个bean工厂的权限,那太危险了,我给你传入指定接口类型的bean工厂参数,你只能调用指定接口中的方法,降低你的权限保证spring的安全。类似于linux上的root用户和普通用户,你得到我的root账号破坏我系统那就不好了。

后置处理器调用顺序

spring有内置的BeanFactoryPostProcessor,程序员也可以自定义BeanFactoryPostProcessor,spring是先调用内置的BeanFactoryPostProcessor 再调用程序员自定义的BeanFactoryPostProcessor ,sping是怎样做到的呢? 答案就是通过BeanDefinitionRegistryPostProcessor来实现。我们看下源码,refresh -> invokeBeanFactoryPostProcessors -> invokeBeanFactoryPostProcessors:

                  .......省略.......     
    //查询BeanDefinitionRegistryPostProcessor的实现类
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    //添加到数组中,后续进行遍历回调
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //存储BeanDefinitionRegistryPostProcessor实现类的名字
                    processedBeans.add(ppName);
                }
            }
            //对BeanDefinitionRegistryPostProcessor设置调用顺序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            //执行BeanDefinitionRegistryPostProcessor
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                   .......省略.......

上面代码的大体意思是,先查询容器中实现PriorityOrdered接口的内置BeanDefinitionRegistryPostProcessor后置处理器并保存到数组中,然后设置处理器的调用顺序,紧接着就调用BeanDefinitionRegistryPostProcessor处理器。如果你跟着笔者的思路进行调试的话,会发现此时spring中只有一个BeanDefinitionRegistryPostProcessor类型的后置处理器,就是ConfigurationClassPostProcessor

spring内置一个ConfigurationClassPostProcessor后置处理器

它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan@ComponentScans注解扫描的包,以及解析@Import等注解。总之爸爸级别的存在,极其的重要!!!以后我会详细详细再详细的讲清楚,特别爽!

我们接着上面的invokeBeanFactoryPostProcessors源码继续看:

//此时ConfigurationClassPostProcessor完成了扫描,我们继续调用其他后置处理器
            //查询程序员提供的BeanDefinitionRegistryPostProcessor后置处理器,
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                //程序员提供的BeanDefinitionRegistryPostProcessor后置处理器必须实现Ordered接口,该接口用于排序
                //spring按顺序调用
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            //设置调用顺序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            //调用程序员提供的后置处理器
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

spring内置的BeanDefinitionRegistryPostProcessor调用之后,spring继续调用实现了Ordered接口的BeanDefinitionRegistryPostProcessor后置处理器,因为此时spring已经完成了扫描加载,所以此时后置处理器既包括spring内置的也包括程序员提供的,我们提供一个BeanDefinitionRegistryPostProcessor后置处理器:

@Component
public class MyBeanFactoryReigtryPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("调用MyBeanFactoryReigtryPostProcessor1");
    }

    @Override
    public int getOrder() {
        return 1;
    }
}


@Component
public class MyBeanFactoryReigtryPostProcessor2 implements BeanDefinitionRegistryPostProcessor, Ordered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("调用MyBeanFactoryReigtryPostProcessor2");
    }

    @Override
    public int getOrder() {
        return 2;
    }
}

打印结果:

自定义BeanDefinitionRegistryPostProcessor后置处理器

最后,spring调用没有实现Ordered接口的BeanDefinitionRegistryPostProcessor后置处理器,包括spring内置的和程序员提供的:

@Component
public class MyBeanFactoryReigtryPostProcessor3 implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
    }
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("调用MyBeanFactoryReigtryPostProcessor3");
    }

}

打印结果:

没有实现Ordered接口的后置处理器

关于BeanDefinitionRegistryPostProcessor我们做个总结:

  1. 先调用spring内置的实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor后置处理器,只有ConfigurationClassPostProcessor。
  2. 再调用实现Ordered接口的BeanDefinitionRegistryPostProcessor后置处理器,包括内置和自定义的。
  3. 最后调用剩下的所有BeanDefinitionRegistryPostProcessor后置处理器。

调用完后继续看源码:

 invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

啥意思?还记得BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor方法吗?其实上面spring调用的是BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,而这行代码调用的是父接口BeanFactoryPostProcessor中的postProcessBeanFactory方法,完成同的功能。 很难!很绕! 调用完BeanDefinitionRegistryPostProcessor紧接着调用BeanFactoryPostProcessor后置处理器。

//查询实现BeanFactoryPostProcessor接口的后置处理器
String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
//实现PriorityOrdered接口的BeanFactoryPostProcessor集合
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//实现Ordered接口的BeanFactoryPostProcessor集合
        List<String> orderedPostProcessorNames = new ArrayList<>();
//啥也没实现的BeanFactoryPostProcessor集合
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    // 首先调用实现PriorityOrdered接口的BeanFactoryPostProcessor
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // 接着调用实现Ordered接口的BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : orderedPostProcessorNames) {
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

        // 最后调剩下所有的BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
        // 清除元数据缓存
        beanFactory.clearMetadataCache();

源码注释讲解的很清楚,spring首先调用实现PriorityOrdered接口的BeanFactoryPostProcessor,接着调用实现Ordered接口的BeanFactoryPostProcessor,最后调剩下所有的BeanFactoryPostProcessor。

以上,我们初探了后置处理器的概念及调用过程。后续我们将深入分析后置处理器。