在prepareContext中,用loader调用load方法,loader是 BeanDefinitionLoader,在BeanDefinitionLoader的构造方法中,
会实例化一个AnnotatedBeanDefinitionReader,在reader的构造方法中,
有一个静态方法registerAnnotationConfigProcessors,里面注册一个ConfigurationClassPostProcessor,
实现了BeanDefinitionRegistryPostProcessor进而实现了BeanFactoryPostProcessor。
而applicationContext在refresh的时候,调用invokeBeanFactoryPostProcessors(beanFactory);
在该方法里,调用了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors这个静态方法,
这里面取出所有的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,并调用两个接口的方法,但是最终都是调用
processConfigBeanDefinitions方法,先取出当前工厂中的beanDefinitions(一般除了系统自己的一些indicator,就是run方法中传入的object数组的内容,一般就是一个启动类),
并不是所有的这些初始的beanDefinitions都会被解析
判断的逻辑(LOGIC_A)是:
1、是否有@Import,@Component,@ImportSource,@ComponentScan之一
2、再判断里面是否有@Bean方法。
这个逻辑也很好理解,因为如果这五个注解都没有,那么基本上也就不是一个想引入其他bean的configuration类。
进入候选之后,PostProcessor生成parser,解析候选,而接下来所有的五个注解解析出来的beanDefinition,包括从内部类,和父类中一共七个通道,
不用再判断是否含有这五个注解,这是因为解析的逻辑也是寻找这五个注解,无非就是麻烦一点。
@Import的解析逻辑,对于被import进来的每一个类processImports方法:

1、如果实现了ImportSelector接口,调用selectImports方法,返回一个字符串数组,遍历字符串数组(classname),再次执行processImports方法(如果实现了ImportSelector的子接口DeferredImportSelector,那么先添加到一个list中,后续在parse方法的最后处理,逻辑和先处理一样)。

2、如果实现了ImportBeanDefinitionRegistrar接口,放到一个容器中,后续在ConfigurationClassBeanDefinitionReader的loadBeanDefinitions处理,还是调用registerBeanDefinitions方法,往工厂中注册beanDefinition

3、如果以上两个接口都没有实现,就当做@Configuration来处理,所以很多的Autoconfiguration上面注解@Configuration是没有意义的,因为@EnableAutoConfiguration就是一个@Import注解,把所有jar包里面spring.factories文件里面,EnableAutoConfiguration对应的值取出来,返回。

也就是说ImportSelector接口返回的类,递归到最后要么是实现ImportBeanDefinitionRegistrar接口,直接向工厂注册beanDefinition,要么是什么也没实现,当做@Configuration来处理

@ComponentScan注解的解析比较简单,看看包里面所有的类,根据filter(默认的有两个过滤器,过滤@component@Named等三个注解),
如果属性basepackage为空,默认是类当前所在的文件夹(ClassUtils.getPackageName)。加载,解析五个注解。
@PropertySource是解析配置文件,键值对形式
@ImportResource是导入spring的配置文件
@Bean是生成一个factoryBeanMethod

@Configuration这个注解其实作用不大

@EnableConfigurationProperties import了EnableConfigurationPropertiesImportSelector,这是个实现了ImportSelector接口的类,按照上面的逻辑,selectImports方法返回

ConfigurationPropertiesBindingPostProcessorRegistrar------------EA

和ConfigurationPropertiesBeanRegistrar-----------------EB

两个实现了ImportBeanDefinitionRegistrar接口的类,按照上面import中2的逻辑,都是向工厂注册bean的方法,

先看EA,registerBeanDefinitions是注册了两个类,meta那个先不管好像没多大用,第二个就是

ConfigurationPropertiesBindingPostProcessor这个类,这是个bean后置处理器,在bean对象生成之后,属性赋值之前调用?postProcessBeforeInitialization方法,看bean有没有注解@ConfigurationProperties,有的话,设置值进去。

再看EB,这个功能有点绕了,是EnableConfigurationProperties注解里的value属性里的值(这里面必须是@ConfigurationProperties的类,简称EC),直接把EC,赋值,注册。如果是一般的被@componentScan到的类,

如果不加上@component注解,是不会被注册到工厂,更别提被bean后处理器检测有没有@ConfigurationProperties了。但是如果是在@EnableConfigurationProperties的value中,就可以不用走扫描这一步,这样就可以引入扫描范围之外的类进来,这个上面和@import的3是一样的,一个类想要被工厂管理,要被扫描到,但是第三方jar包的类,可以通过import进来。当然componentScan可以去扫描第三方的jar包,但是总感觉麻烦了很多,单个引入不方便。

所以@EnableConfigurationProperties其实是有两个功能:引入检测@ConfigurationProperties+@Component(或者相当于这个注解的,比如符合LOGIC_A的内部类和import进来的类)的bean后处理器(重复导入不会出错,因为注册前会判断有没有同类)和在value中直接导入@ConfigurationProperties注解的配置类

为什么import导入的类,不管是不是符合LOGIC_A里的条件,类本身都可以被注册到工厂。但是一个符合LOGIC_A的类的父类,内部类,则要看情况?

A: 走parser的processConfigurationClass(ConfigurationClass configClass) 方法时,类是被封装成configClass当作参数传进来的,会被放到configurationClasses这个map中,递归完成之后会取出来keyset,在reader的loadBeandefinition方法中一一注册。import直接走processConfigurationClass,而ConfigurationClass 的父类是在循环中走的doProcessConfigurationClass方法,父类不会被当作参数传入processConfigurationClass方法中,因此不会被注册(如果加上@component被componentscan扫描到就另当别论,因为componentScan在父类的递归解析之前)。而内部类的解析,会在开始的时候判断是不是符合LOGIC_A,符合,走processConfigurationClass,不符合,跳过。所以内部类有四个注解(除了@component)任何之一,以及@component(这个是自然的)都可以被收到工厂中。而父类有前四个之一就不行,只能有@component才可以

springboot源码之(bean的递归注册)的更多相关文章

  1. springboot源码解析-管中窥豹系列之bean如何生成?(十四)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  2. SpringBoot源码分析之SpringBoot的启动过程

    SpringBoot源码分析之SpringBoot的启动过程 发表于 2017-04-30   |   分类于 springboot  |   0 Comments  |   阅读次数 SpringB ...

  3. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  4. 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 SpringBoot是如何实现自动配置的?--SpringBoot源码(四) 温故而知新,我们来简单回顾一下上 ...

  5. SpringBoot是如何实现自动配置的?--SpringBoot源码(四)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三 ...

  6. 助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 如何分析SpringBoot源码模块及结构?--SpringBoot源码(二) 上一篇分析了SpringBoo ...

  7. SpringBoot内置的各种Starter是怎样构建的?--SpringBoot源码(六)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五) 温 ...

  8. SpringBoot的启动流程是怎样的?SpringBoot源码(七)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 SpringBoot内置的各种Starter是怎样构建的? SpringBoot源码(六) 温故而知新, ...

  9. SpringBoot内置生命周期事件详解 SpringBoot源码(十)

    SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringBoot事件监听 ...

  10. springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

随机推荐

  1. html5,dom操作1

    <body> <script>function hwd(){ var bb=document.getElementById('bt');// alert(bb.innerHTM ...

  2. MSG结构体和WndProc窗口过程详解

    MSG结构体和WndProc窗口过程对于Windows编程非常重要,如果不了解它们,可以说就没有学会Windows编程. MSG结构体 MSG 结构体用来表示一条消息,各个字段的含义如下: typed ...

  3. python爬虫——绕开杂乱无章的代码和堵住请求的302异常(2)

    淘宝那次抓包,居然发现不了要抓的url位置,三星中... 不过不怕,不就是没法快点分析出包嘛,下次用phantomJS硬杠,或者有时间慢慢分析也好. 今天挑战一个稍微好爬的网站:狗搬家(误) 打开后台 ...

  4. 用ab的post方式进行测试

    一.Ab是常用的性能测试工具,因为它支持windows…… 通常使用的命令是ab –c –n –k -r,分别表示:模拟终端数.发送包数.请求是否带keepalive.忽略错误,默认都是以GET方式去 ...

  5. TCP之种种连接异常

    1. connect出错: (1) 若TCP客户端没有收到syn分节的响应,则返回ETIMEOUT错误:调用connect函数时,内核发送一个syn,若无响应则等待6s后再发送一个,若仍然无响应则等待 ...

  6. Quick Union

    Quick Union quick union就是快速连接 和quick find相同,也是构建一个数组id[],不过存的值换一种理解: 每个数组内的元素看做一个结点,结点内的值即id[i]看做i的前 ...

  7. 清华集训2017 Day 2简要题解

    *注意:这套题目题面请在loj / uoj查看 从这里开始 题目列表(loj) Problem A 小 Y 和地铁 Problem B 小 Y 和二叉树 Problem C 小 Y 和恐怖的奴隶主 训 ...

  8. eclipse中如何打开工作空间里面已经有的项目

    File->Import->打开大类General->找到小类Existing Projects info Workspace->选择Select root dirctory, ...

  9. Bootstrap3基础 warning/active... 表格的状态类(不同的背景色)

      内容 参数   OS   Windows 10 x64   browser   Firefox 65.0.2   framework     Bootstrap 3.3.7   editor    ...

  10. jquery 获取当前点击的是谁

    //今天早上有人问这个问题 想着没写过jquery的笔记 //那就随便写一下吧 下面两个方法 根据不同情况而定用哪种方法$(".class").click(function(){ ...