在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. samba服务器笔记 (一)

    Samba安装 samba:主服务包:samba-client:客户端:samba-common:通用工具:samba4-libs:库:samba-winbind:windows域映射:samba-w ...

  2. jquery首页图片轮播

    css样式 .bannerBox {position: relative;width: 100%;height: 348px;margin:0px auto;}.bannerBox .bannerLi ...

  3. Vue 组件&组件之间的通信 之组件的介绍

    什么是组件? 组件Component,可扩展HTML元素,封装可重用的代码.通俗的来说,组件将可重用的HTML元素封装成为标签方便复用: 组件的使用: 1.使用全局的方法Vue.extend创建构造器 ...

  4. Docker Kubernetes 常用命令

    Docker Kubernetes 常用命令 增 # 通过文件名或标准输入创建资源. kubectl create # 读取指定文件内容,进行创建.(配置文件可指定json,yaml文件). kube ...

  5. Python Redis 常用操作

    delete(*names) # 根据删除redis中的任意数据类型 exists(name) # 检测redis的name是否存在 keys(pattern='*') # 根据模型获取redis的n ...

  6. es日常维护

    1.查看es日志curl -XGET http://10.26.41.60:9200/xdm-logs-2018.08.22?pretty=true 2.删除es日志curl -XDELETE 'ht ...

  7. Python实战:网络爬虫都能干什么?

    整站下载器:siteSucker https://blog.csdn.net/l_215851356/article/details/54377582 http://python.jobbole.co ...

  8. 使用VS Code调试Node

    1.双击打开vscode 2.找到底层面板 把ctrl改成LF 2. 3.打开文件夹,建立项目test 4.新建hellow.js 输入: var name='world'; var s='hello ...

  9. CSS基础学习(一) 之 line-height 与 height 属性区别

    官方定义: height:定义了了元素的高度.默认情况下,该属性订了 content area(内容区域) 的高度.如果box-sizing属性设置为 border-box,那么height就表示bo ...

  10. IOS面试题2018/11/17

    1.设计模式是什么?你知道哪些设计模式? 设计模式是一种编码经验,就是一种成熟的逻辑去处理某一种类型的事情. 1.MVC模式:model view controller,把模型,视图,控制器 层进行解 ...