spring源码-invokeBeanFactoryPostProcessors()以及registerBeanPostProcessors()

在这两个方法执行之前,已经做了如下操作:

  • 创建了DefaultListableBeanFactory
  • beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
  • new RootBeanDefinition(ConfigurationClassPostProcessor.class)
  • new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class)
  • new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)
  • beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))
  • beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this))

1.invokeBeanFactoryPostProcessors()

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.addBeanFactoryPostProcessor(new XXXBeanFactoryPostProcessor);
contest.refresh();
    public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
        return this.beanFactoryPostProcessors;
    }

这里this.beanFactoryPostProcessors就是通过context.addBeanFactoryPostProcessor()手动添加的,如果没有添加,就为空。

invokeBeanFactoryPostProcessors()执行流程:

  • 1)执行通过ApplicationContext手动添加进来的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
  • 2)执行BeanFactory中实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法。这里会将ConfigurationClassPostProcessor的BeanDefinition实例化出来,并进行调用。
  • 3)执行BeanFactory中实现了Ordered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
  • 4)执行BeanFactory中其他的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法(这里是个循环,如果新注册了BeanDefinitionRegistryPostProcessor,会继续循环进行处理)
  • 5)执行上面所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法
  • 6)执行通过ApplicationContext手动添加进来的BeanFactoryPostProcessor的postProcessBeanFactory()方法
  • 7)执行BeanFactory中实现了PriorityOrdered接口的BeanFactoryPostProcessor的postProcessBeanFactory()方法
  • 8)执行BeanFactory中实现了Ordered接口的BeanFactoryPostProcessor的postProcessBeanFactory()方法
  • 9)执行BeanFactory中其他的BeanFactoryPostProcessor的postProcessBeanFactory()方法

1.1 ConfigurationClassPostProcessor

1.1.1 processConfigBeanDefinitions()

执行流程:

  • 1)拿到beanFactory容器里面注册的BeanDefinitions,这里只能拿到传入的配置类(这是重点)以及系统自己注册的那些BeanDefinition(ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等)
  • 2)判断这些BD,哪些是配置类。
    Full配置类:@Configuration注解。
    Lite配置类:@Configuration注解,其proxyBeanMethods为false;有注解@Component、@ComponentScan、@Import、@ImportResource;类里面有加了@Bean注解的方法。
  • 3)对配置类进行排序
  • 4)do ... while(!candidates.isEmpty()) 进行循环解析
  • 4-1)parser.parse(candidates),parser是ConfigurationClassParser
       A)for循环解析candidates
       A-1)this.conditionEvaluator.shouldSkip()处理@Conditional条件注解
       A-2)do...while(sourceClass != null)处理doProcessConfigurationClass,这里循环处理父类
          a)@Component注解,处理内部类
          b)@PropertySource注解,属性配置文件
          c)@ComponentScan、@ComponentScans会构造扫描器进行扫描,遍历扫描得到的BD是否是配置类并进行处理
          d)@Import(三种情况:ImportSelector、ImportBeanDefinitionRegistrar、普通的类(直接当作配置类)),其中DeferredImportSelector,this.deferredImportSelectorHandler.handle()这里只是存了一下。
          e)@ImportResource,导入一个xml配置文件
          f)@Bean方法
          g)处理实现的接口里面的@Bean的default方法
       A-3)this.configurationClasses.put(configClass, configClass)
       B)this.deferredImportSelectorHandler.process();在本轮配置类解析完之后再执行延迟的DeferredImportSelector。
  • 4-2)this.reader.loadBeanDefinitions(configClasses); (生成很多BeanDefinition)将被导入的类@Import以及@Component内部类生成BD注册到Spring容器中;处理@Bean生成的BD;处理@ImportResource导入的xml配置文件;处理@Import导入的ImportBeanDefinitionRegistrar
  • 4-3)筛选出新增的BeanDefinition,并筛选出没有被解析的配置类继续进行处理。@Bean引入的类,其className为null,会判定其不是配置类。

BeanDefinition的覆盖问题:

  • 1)@Component覆盖@Component,对应的名字相同,会抛异常ConflictingBeanDefinitionException:ClassPathBeanDefinitionScanner#checkCandidate。
  • 2)@Bean覆盖@Bean,比如多个重载方法(参数个数不同),不会报错。ConfigurationClassBeanDefinitionReader#isOverriddenByExistingDefinition(),如果相同,则直接返回不会创建新的BD。
  • 3)@Bean覆盖@Component(先扫描,再处理@Bean),如果允许覆盖(默认允许),则@Bean的BD会覆盖@Component的BD。

1.1.2 postProcessBeanFactory()

处理流程:

  • 1)这里会将是Full配置类的BeanDefinition筛选出来
  • 2)对这些Full配置类,生成代理类,并将beanDef.setBeanClass(enhancedClass)的类设置为代理类

这里代理类的增强逻辑是:

    private static final Callback[] CALLBACKS = new Callback[] {
            new BeanMethodInterceptor(),
            new BeanFactoryAwareMethodInterceptor(),
            NoOp.INSTANCE
    };

核心是BeanMethodInterceptor,这里会进行处理下面的问题。

@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        System.out.println(orderService());
        System.out.println(orderService());
        return new UserService();
    }

    @Bean
    public OrderService orderService() {
        return new OrderService();
    }
}

这里主要解决的就是上面的这种问题,就是上面的orderService()返回的是同一个对象还是不同对象?如果是Full配置类,则返回的是相同对象,如果不是Full配置类,则返回的是不同的对象。

这里的orderService()除了上面在userService()中调用,还在创建@Bean的单例时会调用。

2.registerBeanPostProcessors()

上面的步骤完成了扫描(这个过程中会扫描出程序员可自己定义的BeanPostProcessor),在这一步就会把BeanFactory中所有的BeanPostProcessor找出来并实例化得到一个对象,并添加到BeanFactory中去(属性beanPostProcessors),最后再重新添加一个ApplicationListenerDetector对象(之前其实就添加了过,这里是为了把ApplicationListenerDetector移动到最后)。

步骤:

  • 1)首先实例化并注册(放到容器的属性beanPostProcessors:CopyOnWriteArrayList)PriorityOrdered的BeanPostProcessor,如果是MergedBeanDefinitionPostProcessor,则将其加入到internalPostProcessors
  • 2)其次实例化并注册Ordered的BeanPostProcessor,如果是MergedBeanDefinitionPostProcessor,则将其加入到internalPostProcessors
  • 3)其他的BeanPostProcessor,如果是MergedBeanDefinitionPostProcessor,则将其加入到internalPostProcessors
  • 4)注册internalPostProcessors,也即将internalPostProcessors移到末尾
  • 5)最后再添加ApplicationListenerDetector

MergedBeanDefinitionPostProcessor表示系统内部的BeanPostProcessor,比如AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor就实现了该接口。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容