在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. 发布WebApi项目时包含XML文档文件

    Open your publishprofile (*.pubxml) and include this code into "Project" element: <Item ...

  2. Python 第五阶段 学习记录之----rabbmit

    消息服务器rabbmit RabbitMQ 消息队列 python里有两个Q, threading queue.不同线程间数据交互 进程Queue: 不同进程间交互这个说法是错误的. 这个是用于父进程 ...

  3. Linux基础命令---cancel取消打印任务

    cancel cancel指令用来取消已经存在的打印任务. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.Fedora.openSUSE.SUSE.   1.语法       ...

  4. idea 编译报错 未结束的字符串字面值,非法的类型开始

    1.修改编码 全局编码设置: File -> Other Settings -> Default Settings->file encoding 工程编码设置: File -> ...

  5. 使用查询分析器和SQLCMD分别登录远程的SQL2005的1434端口

    SQLCMD是操作SQLSERVER的一个命令行工具, 而查询分析器是它的图形工具     查询分析器(SQL2005下叫managerment studio),连接远程的SQLSERVER2005, ...

  6. Weighted Quick Union

    Weighted Quick Union即: 在Quick Union的基础上对结点加权(weighted),在parent[i]基础上增加一个size[i]. 用来存储该结点(site)的所有子结点 ...

  7. 自制操作系统Antz(5)——深入理解保护模式与进入方法

    Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址:https://www.cnblogs. ...

  8. 性能测试监控工具nmon详解和分析

    性能测试监控工具nmon详解和分析 1.命令安装 1.查看liunx版本版本x86_64_14i 目录:cd /nmon/logs/ 版本x86_64_14i [root@localhost u06] ...

  9. Learning-Python【18】:Python常用模块(1)—— time、datetime、randrom

    time 模块:与时间相关的功能的模块 在 Python 中,时间分为三种: 1.时间戳:是一个时间的表示,根据不同的语言,可以是整数或浮点数,是从1970年1月1日0时0分0秒到现在经历的秒数 2. ...

  10. .NET Core 配置GC工作模式与内存的影响

    .NET Core 配置GC工作模式与内存的影响 .NET Core GC 原文:https://blog.markvincze.com/troubleshooting-high-memory-usa ...