在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. spring boot + vue + element-ui全栈开发入门——前后端整合开发

    一.配置 思路是通过node的跨域配置来调用spring boot的rest api. 修改config\index.js文件,设置跨域配置proxyTable: proxyTable: { '/ap ...

  2. JSONModel(I)

    JSONModel使用简介 JSONModel 只需要将你的 model 类继承自 JSONModel ,而同时 model 中的属性名又恰巧可以和 JSON 数据中的 key 名字一样的话,那么非常 ...

  3. Django框架---- 信号

    Django中的信号及其用法 Django中提供了"信号调度",用于在框架执行操作时解耦. 一些动作发生的时候,系统会根据信号定义的函数执行相应的操作 Django中内置的sign ...

  4. Linux:command not found

    最近老是遇到command not found 这个问题,然后就上网查到什么文件底下export什么变量啊.后来次数多了,发现不对劲.后来上网查了一下,原来切换到root用户要使用su -,而不是su ...

  5. JS中几种常见的高阶函数

    高阶函数:英文叫Higher-order function.JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数 ...

  6. CSS 页面布局、后台管理示例

    CSS 页面布局.后台管理示例 页面布局 1.头部菜单 2.中间内容/中间左侧菜单 3.底部内容 <div class='pg-header'> <div style='width: ...

  7. Codeforces 932G Palindrome Partition - 回文树 - 动态规划

    题目传送门 通往???的传送点 通往神秘地带的传送点 通往未知地带的传送点 题目大意 给定一个串$s$,要求将$s$划分为$t_{1}t_{2}\cdots t_{k}$,其中$2\mid k$,且$ ...

  8. build tool 的简单认知

    Build Tool 什么是Build Tool(构建工具)? 构建工具是从源代码自动创建可执行应用程序的程序(例如.apk for android app).构建包括将代码编译,链接和打包成可用或可 ...

  9. adb shell 命令之----pm

    常用的用法: 查看已经安装的包: pm list packages 查看已经安装的包以及apk路径(-3:只看第三方应用: -s:只看系统应用) -f: see their associated fi ...

  10. yum downloadonly模式,保存所需软件及其依赖包

    command: sudo yum install --downloadonly --downloaddir='yourderictory'