zoukankan      html  css  js  c++  java
  • Spring源码解读之BeanFactoryPostProcessor的处理

    前言

        前段时间旁听了某课堂两节Spring源码解析课,刚好最近自己又在重新学习中,便在这里记录一下学习所得。我之前写过一篇博文,是介绍BeanFactoryPostProcessor跟BeanPostProcessor是如何发挥作用的,当时觉得讲的还行,但是现在看来,太粗劣了,很多地方没涉及到,而且重点都被我忽略了,简直就是蠢得不行。现在就用这篇文章弥补一下前文中对BeanFactoryPostProcessor的讲解,争取把重点讲到,至于BeanPostProcessor,由于涉及到的东西太多,限于本人目前的水平只能作罢,待后面感悟成熟了再来补充。

    我们以AnnotationConfigApplicationContext为例来构建测试类,先附上此次打断点调试的三个简约到极致的测试类:

    1 public class SpringTest {
    2 
    3     public static void main(String[] args) {
    4         // 从这两行代码,实地跟踪考察Spring中的流程
    5         AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanConfig.class);
    6         applicationContext.getBean(Teacher.class).teach();
    7     }
    8 }
     1 package myPackage;
     2 import org.springframework.stereotype.Service;
     3 
     4 @Service
     5 public class Teacher {
     6     public Teacher () {
     7         System.out.println("Teacher init");
     8     }
     9     public void teach () {
    10         System.out.println("teach");
    11     }
    12 }
    1 package myPackage;
    2 import org.springframework.context.annotation.ComponentScan;
    3 
    4 @ComponentScan("myPackage")
    5 public class ScanConfig {
    6 }

    1、洞悉启动容器时的准备工作

    熟悉一些Spring的道友应该都知道,refresh方法中的invokeBeanFactoryPostProcessors方法实现了对BeanFactoryPostProcessor实现类的处理。大家如果只看invokeBeanFactoryPostProcessors方法的话,不会发现有何异常之处,此方法虽然较长,但是处理逻辑很清晰,先对重写了BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor方法的实现类进行处理,后对重写了BeanFactoryPostProcessor的方法的实现类做了处理。但是如果心细的话,你会发现问题,Spring是如何将@ComponentScan("myPackage")注解发挥作用的?这时带着这样的问题,我们再回过头来看容器的构造方法,就会在这平实的表面下发现意想不到的 "杀机"。

    1 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    2         this();
    3         register(annotatedClasses);
    4         refresh();
    5     }

    通过这个构造方法可以知道,在第二行将我们的测试类ScanConfig 注册进了容器中,但这只是注册,注册之后是如何调用如何实现了@ComponentScan("myPackage")这个注解的包扫描的呢?这时我们将目光锁定this()方法。点进去后发现是这样的:

    1 public AnnotationConfigApplicationContext() {
    2         this.reader = new AnnotatedBeanDefinitionReader(this);
    3         this.scanner = new ClassPathBeanDefinitionScanner(this);
    4     }

    在第二行新建reader对象时,调用了这个构造方法:

    1 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    3         Assert.notNull(environment, "Environment must not be null");
    4         this.registry = registry;
    5         this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    6         AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    7     }

    其中的第六行,最终调用了AnnotationConfigUtils#registerAnnotationConfigProcessors方法,而就是在这个方法中完成了对多个重要Bean的注册,跟我们关系比较大的有以下几个:

     1         // BeanDefinitionHolder只是存放BD的,里面有三个属性:BD对象、beanName以及别名组成的String[]
     2         Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
     3         // 注册最关键的类,对应的类为ConfigurationClassPostProcessor,父类的父类是BeanFactoryPostProcessor
     4         if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
     5             RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
     6             def.setSource(source);
     7             // 将BD注入进容器中,没经过什么处理,只是放入了DefaultListableBeanFactory中的beanDefinitionMap跟存放beanName的list中
     8             beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
     9         }
    10         // 此类实现了BeanPostProcessor,用于处理@Autowired、@Value注解
    11         if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    12             RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    13             def.setSource(source);
    14             beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    15         }
    16         // 此类也实现了BeanPostProcessor,用于处理有@Required注解的方法
    17         if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    18             RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
    19             def.setSource(source);
    20             beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    21         }

    其中第一个对应的类就是我们重点关注的对象 ConfigurationClassPostProcessor类,查看此类的组成,发现它实现了BeanDefinitionRegistryPostProcessor接口,而此接口正是BeanFactoryPostProcessor的子接口。此时,萦绕在我们心头的迷雾开始渐渐散开,我们仿佛能抓到一闪而过的逻辑走向,现在让我们带着之前的发现,进入正主invokeBeanFactoryPostProcessors方法中一探究竟。

    2、invokeBeanFactoryPostProcessors

    该方法位于AbstractApplicationContext的refresh方法中,如下所示:

     1 public void refresh() throws BeansException, IllegalStateException {
     2         synchronized (this.startupShutdownMonitor) {
     3             // Prepare this context for refreshing.
     4             prepareRefresh();
     5 
     6             // Tell the subclass to refresh the internal bean factory.
     7             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
     8 
     9             // Prepare the bean factory for use in this context.
    10             prepareBeanFactory(beanFactory);
    11 
    12             try {
    13                 // Allows post-processing of the bean factory in context subclasses.
    14                 postProcessBeanFactory(beanFactory);
    15 
    16                 // Invoke factory processors registered as beans in the context. 
    17                 invokeBeanFactoryPostProcessors(beanFactory);

    即第17行调用的方法。初学者看到这个方法的内部实现时,会发现此方法无外乎是找到所有实现了BeanDefinitionRegistryPostProcessor跟BeanFactoryPostProcessor接口的类,按照优先级(实现了PriorityOrdered接口的先于实现了Ordered接口,前两者均先于未实现的,且同一类中按照getOrder方法返回值排优先级)顺序执行它们的重写方法,先执行BeanDefinitionRegistryPostProcessor的重写方法,再执行BeanFactoryPostProcessor的重写方法,很容易理解的逻辑。但是现在我们是带着前面准备工作中得到的线索来的,此时再看,就能透过这个方法朴实的外表发现它潜藏的凶险,它如平地一声雷般让人猛地惊出一身冷汗。

    我们打断点进入PostProcessorRegistrationDelegate类中的下面方法中

    1     public static void invokeBeanFactoryPostProcessors(
    2             ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {}

    先略过开始对手动添加进去的beanFactoryPostProcessors处理逻辑,看后面的部分代码(由于此方法代码较多,此处就不全部粘贴出来了,因为逻辑很好理解,所以只粘贴重点):

     1             String[] postProcessorNames =
     2                     beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
     3 
     4             // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
     5             List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
     6             // 1.2 先处理实现了PriorityOrdered的类
     7             for (String ppName : postProcessorNames) {
     8                 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
     9                     // 此处通过getBean来生成ConfigurationClassPostProcessor实例对象
    10                     priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    11                     processedBeans.add(ppName);
    12                 }
    13             }
    14             // 就一个对象,有啥好排序的
    15             sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
    16             registryPostProcessors.addAll(priorityOrderedPostProcessors);
    17             // 执行ConfigurationClassPostProcessor中的重写方法postProcessBeanDefinitionRegistry,会将所有加了注解的类注册到容器中
    18             // 此处才是整个invokeBeanFactoryPostProcessors方法的核心所在,需要详述 下面进入ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry中一探究竟
    19             invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

    debug到第一行的时候,会发现此处获取到的postProcessorNames 中只有一个值,就是前面准备工作中通过硬编码往容器里注册的ConfigurationClassPostProcessor类。下面的逻辑就是进行各种判断,最后在第19行完成了对ConfigurationClassPostProcessor中postProcessBeanDefinitionRegistry方法的调用。

    就是在这个后置处理方法中,完成了@ComponentScan("myPackage")中对包的扫描,完成了所有Bean的注册。执行完这个方法后,你会发现beanDefinitionMap中所有应该容器管理的类全都齐活了,包括其他的后置处理器。这样,后面继续调用beanFactory.getBeanNamesForType方法时,获取到的是所有满足条件的类,后面的工作就会有条不紊的开展下去了。

    总结

        本文着重追溯了BeanFactoryPostProcessor及其子接口是如何在Spring中发挥作用的。先通过Spring初始化容器时注册进去的ConfigurationClassPostProcessor类触发对其他类的扫描,待全部注册进容器后,再从容器中取对应的BeanFactoryPostProcessor及其子接口的实现类,逐一对重写方法进行调用。

    虽然魔鬼在细节,但这也正是解读源码的快乐之处,不是吗?

  • 相关阅读:
    Palindrome Partitioning
    triangle
    Populating Next Right Pointers in Each Node(I and II)
    分苹果(网易)
    Flatten Binary Tree to Linked List
    Construct Binary Tree from Inorder and Postorder Traversal(根据中序遍历和后序遍历构建二叉树)
    iOS系统navigationBar背景色,文字颜色处理
    登录,注销
    ios 文字上下滚动效果Demo
    经常崩溃就是数组字典引起的
  • 原文地址:https://www.cnblogs.com/zzq6032010/p/11031214.html
Copyright © 2011-2022 走看看