springboot 注解处理流程


传送:

Spring大观园,我有过的困惑或许你也有!


几个关键类

BeanDefinition

是一个接口,实现有RootBeanDefination,AnnotatedGenericBeanDefinition等。
用来存储Bean定义的一些信息的,比如Class,Scope,init-methon,等等。

BeanDefinitionHolder

这是BeanDefination的包装类,用来存储BeanDefinition,name(bean名称)以及aliases(bean别名)等

BeanFactory

BeanFactory 创建和管理bean,同时作为bean的容器存放bean的定义以及bean实例等。AbstractBeanFactory继承了BeanFactory接口,并且实现了大部分BeanFactory的功能,通过其getBean方法创建bean,没有就创建,并缓存,已创建了就直接返回,所以名字叫getBean,其内部还有createBean的方法来创建bean。

Environment

提供了应用所需要的运行时环境信息,如各种propertySource.

AnnotatedBeanDefinitionReader

负责创建bean定义并注册到容器中,其主动注册了几个核心处理器(BeanFactoryPostProcessor),如ConfigurationClassPostProcessor 实现配置类解析,组件扫描。

AnnotationConfigApplicationContext

基于注解的容器类,它实现了BeanFactory和BeanDefinitionRegistry两个接口,拥有Bean对象的管理和BeanDefinition注册功能。同时这个类中有DefaultListableBeanFactory, xxxEnvironment 和AnnotatedBeanDefinitionReader等等,协调这几个对象,让他们各司其职,协同工作完成spring的初始化和bean的创建。
AnnotationConfigApplicationContext的实际的对象管理和BeanDefinition注册是委托DefaultListableBeanFactory(也实现了BeanFactory和BeanDefinitionRegistry接口)来实现的。

知晓bean创建 两步走

spring的ioc有自己的一套bean管理机制,在他的内部创建对象除了class信息之外还要其他信息,如是否单例,是否延迟初始化等。通过bean定义(BeanDefinition)来封装class以及其他的一些信息。
所以bean实例的创建一般是2步
第一步是创建bean的定义(BeanDefinition)对象,放入到容器中,
第二部是根据bean的定义信息创建bean的实例对象,根据条件放入容器中。
创建bean的实例对象有分几个步骤

  1. 从BeanDefinition 中拿到Class信息
  2. 反射的方式 实例化 Class 得到一个对象实例
  3. 经历spring中配置的若干个创建bean的几个步骤,对对象实例进行操作后完成bean的创建。这几个步骤是bean的整个生命周期的一部分;
理解Bean和对象的区别
实例 类型
jvm 对象实例 class类
spring bean beanDefinition

beanDefinition(bean定义) 是bean的描述,拥有许多bean的描述信息(包括了class信息),jvm层面反射创建对象(对象由jvm管理),spring需要再对这个反射创建的对象再做一些操作后这个对象才叫做bean(bean由spring管理);由此看来bean创建与对象创建的区别就是多了几次spring规定的操作,这些操作构成了bean的生命周期。

BeanFactoryPostProcessor和BeanPostProcessor

spring两步走,创建bean定义,根据bean定义创建bean;

  • BeanFactoryPostProcessor的操作对象是bean工厂,执行的操作是往工厂中添加BeanDefinition。
  • BeanPostProcessor的操作对象是bean,作用于bean创建的生命周期中。

Spring中Bean大致可以分为两类,应用类Bean(被应用程序使用)和功能性Bean(被Spring使用)。从上边介绍可知BeanFactoryPostProcessor和BeanPostProcessor的实现类就是功能性bean,给spring提供服务,spring使用他们之前必然通过getBean的方式创建他们.

  • BeanFactoryPostProcessor,在refresh方法中调用invokeBeanFactoryPostProcessors方法时创建,
  • BeanPostProcessor的实现bean,在registerBeanPostProcessors方法中创建.
  • 其它应用类Bean,在默认的finishBeanFactoryInitialization方法中创建.
AnnotatedBeanDefinitionReader
  • 在构造函数中做了两件关键事宜:
    1.BeanFactory中注册与注解相关的xxxProcessor处理器,用于解析配置类,扫描bean
    2.注册配置类
    表面分别来看:
  • 1.注册处理器: xxxApplicationContext的构造方法中会创建AnnotatedBeanDefinitionReader,reader的构造函数中 通过AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)往BeanDefinitionRegistry 中注册 注解配置相关的 processors,重点看ConfigurationClassPostProcessor (解析配置类,扫描bean),AutowiredAnnotationBeanPostProcessor(自动注入处理)
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        // 调用了registerAnnotationConfigProcessors方法
        registerAnnotationConfigProcessors(registry, null);
    }

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);    

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            // 看见没有,在这里注册了ConfigurationClassPostProcessor类。
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            // 主要是调用了registerPostProcessor来进行注册的。
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            // 同时也注册了另一个重要类AutowiredAnnotationBeanPostProcessor
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // ...

        return beanDefs;
    }
    1. 注册配置类的源码流程如下:
    public void registerBean(Class<?> annotatedClass) {
        doRegisterBean(annotatedClass, null, null, null);
    }


    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

        // 创建BeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        // 生成bean name
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        
        // ...省去了其它代码

        // 创建BeanDefinitionHolder,它是BeanDefiniton的一个包装类,包含BeanDefiniton对象和它的名字
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        // 最后调用registerBeanDefinition
        // 其内部是调用beanFactory的registerBeanDefinition,代码如下:
        // this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
        //上文说过,AnnotationConfigApplicationContext是委托DefaultListableBeanFactory来注册BeanDefinition和管理Bean的
        //DefaultListableBeanFactory中的registerBeanDefinition实现为
        //this.beanDefinitionMap.put(beanName, beanDefinition);
        //可以看出,最终是将beanDefinition放到beanDefinitionMap中。所有的beanDefinition都会放到这个map中,以beanName为主键。如果一个beanDefinition有多个别名,那个它会被注册多次。
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    } 
!!!小结
  1. AnnotationConfigApplicationContext通过AnnotatedBeanDefinitionReader
    1.1 注册几个核心xxxprocessor如ConfigurationClassPostProcessor;
    1.2 注册主配置类,

  2. 其内部是委托DefaultListableBeanFactory完成BeanDefinition的注册,

  3. 注册的结果是BeanDefinition被存储在一个Map中,以beanName为key,以BeanDefinition对象为值。

  4. spring通过BeanFactoryPostProcessor开放接口,提供了参与操作beanFactory,注册(修改)BeanDefinition的机会。
    4.1 BeanFactoryPostProcessor调用时机在方法invokeBeanFactoryPostProcessors中, 通过对 所有BeanFactoryPostProcessor实现类的实例化和方法调用,往容器中注册了所有的BeanDefinition;尤其是 ConfigurationClassPostProcessor实现了我们最关注的基于注解的配置类解析,bean扫描等功能)

  5. spring通过BeanPostProcessor开放接口,提供了参与bean构建的机会。
    5.1 在registerBeanPostProcessors(beanFactory)注册,
    5.2 在finishBeanFactoryInitialization(beanFactory)实例化Bean的时候使用


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