个人博客:槿苏的知识铺

一、什么是自动装配

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot在启动时会扫描外部引用jar包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到Spring容器,并执行类中定义的各种操作。对于外部jar包来说,只需要按照SpringBoot定义的标准,就能将自己的功能装配到SpringBoot中。

二、自动装配的实现原理

自动装配的实现,离不开SpringBootApplication这个核心注解。查看这个注解的源码,我们会发现在SpringBootApplication注解上,存在着几个注解,其中SpringBootConfigurationEnableAutoConfigurationComponentScan这三个注解是需要我们注意的。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

(1) ComponentScan

扫描被@Component 、@Service注解的bean,该注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如SpringBootApplication注解源码所示,容器中将排除TypeExcludeFilterh和AutoConfigurationExcludeFilter。

(2) EnableAutoConfiguration

启用 SpringBoot 的自动配置机制

(3) Configuration

允许在上下文中注册额外的 bean 或导入其他配置类

2.1 EnableAutoConfiguration详解

@EnableAutoConfiguration是实现自动装配的重要注解,在这个注解上存在以下两个注解:AutoConfigurationPackageImport

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
2.1.1 AutoConfigurationPackage

表示对于标注该注解的类的包,应当使用AutoConfigurationPackages注册。实质上,它负责保存标注相关注解的类的所在包路径。使用一个BasePackage类,保存这个路径。然后使用@Import注解将其注入到ioc容器中。这样,可以在容器中拿到该路径。

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
}

查看AutoConfigurationPackages中的Registrar这个类的源码,在Registrar#registerBeanDefinitions方法中有这样一句代码new PackageImport(metadata).getPackageName(),查看PackageImport的构造器后不难发现,这里获取的是StandardAnnotationMetadata这个实例所在的包名。

/**
* metadata: 实际上是 StandardAnnotationMetadata 实例。
* metadata#getClassName(): 获取标注 @AutoConfigurationPackage 注解的类的全限定名。
* ClassUtils.getPackageName(…): 获取其所在包。
*/
PackageImport(AnnotationMetadata metadata) {
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
}

此时再回去看Registrar#registerBeanDefinitions中调用的AutoConfigurationPackages#register方法

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// BEAN:AutoConfigurationPackages类的全限定名
// 此时判断BeanDefinitionRegistry中是否存在以BEAN作为beanName的BeanDefinition对象
// 如果不存在,走else方法,构造了一个BackPackages实例,进行注册
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
addBasePackages(constructorArguments, packageNames));
} else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
2.1.2 Import(AutoConfigurationImportSelector.class)

它是利用AutoConfigurationImportSelector机制再来给容器中批量导入一些配置东西的,接下来带大家了解究竟导入了哪些内容。

/**
* AutoConfigurationImportSelector类中存在一个叫selectImports的方法,就是我们到底要向容器中导入哪些
* 内容,都会在这里进行扫描并导入。
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 判断EnableAutoConfiguration是否开启默认开启true
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 1.加载META-INF/spring-autoconfigure-metadata.properties 文件
// 2.从中获取所有符合条件的支持自动装配的类
// 自动配置类全名.条件=条件的值
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 获取AutoConfigurationEntry
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

接下来重点看getAutoConfigurationEntry(annotationMetadata)方法,利用这个方法向容器中批量导入一些默认支持自动配置的类,当你理解了这部分内容之后,就基本了解了Spring Boot是如何进行自动装配的,废话不多说,让我们进入正题。

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 判断EnableAutoConfiguration是否开启默认开启true
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取注解属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 调用getCandidateConfigurations(annotationMetadata, attributes),利用loadSpringFactories(ClassLoader classLoader)加载当前系统所有的META-INF/spring.factories文件,得到默认支持的自动配置的类的列表
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去除重复的 configuration
configurations = removeDuplicates(configurations);
// 获取到SpringBootApplication上exclude和excludeName配置的需要排除的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查configurations是否含有exclusions中的类
checkExcludedClasses(configurations, exclusions);
// 将exclusions中的类从configurations中排除
configurations.removeAll(exclusions);
// 对所有候选的自动配置类进行筛选,
// 比如ConditionalOnProperty 当属性存在时
// ConditionalOnClass 当class存在
// ConditionalOnMissingClass 当这个clas不存在时才去配置
// 过滤器
configurations = getConfigurationClassFilter().filter(configurations);
// 将自动配置的类,导入事件监听器,并触发fireAutoConfigurationImportEvents事件
// 加载META-INF\spring.factories中的AutoConfigurationImportListener
fireAutoConfigurationImportEvents(configurations, exclusions);
// 创建AutoConfigurationEntry对象
return new AutoConfigurationEntry(configurations, exclusions);
}

从源码中理解Spring Boot自动装配原理的更多相关文章

  1. Spring Boot 自动装配原理

    Spring Boot 自动装配原理 Spring Boot 在启动之前还有一系列的准备工作,比如:推断 web 应用类型,设置初始化器,设置监听器,启动各种监听器,准备环境,创建 applicati ...

  2. Spring Boot系列(二):Spring Boot自动装配原理解析

    一.Spring Boot整合第三方组件(Redis为例) 1.加依赖 <!--redis--> <dependency> <groupId>org.springf ...

  3. Spring Boot自动装配原理源码分析

    1.环境准备 使用IDEA Spring Initializr快速创建一个Spring Boot项目 添加一个Controller类 @RestController public class Hell ...

  4. Spring Boot自动配置原理(转)

    第3章 Spring Boot自动配置原理 3.1 SpringBoot的核心组件模块 首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量: 我们cd到spring-boot- ...

  5. Spring Boot自动装配

    前言 一些朋友问我怎么读源码,这篇文章结合我看源码时候一些思路给大家聊聊,我主要从这三个方向出发: 确定目标,这个目标要是一个具体,不要一上来我要看懂Spring,这是不可能的,目标要这么来定,比如看 ...

  6. Spring Boot 自动装配(二)

    目录 目录 前言 1.起源 2.Spring Boot 自动装配实现 2.1.@EnableAutoConfiguration 实现 2.1.1. 获取默认包扫描路径 2.1.2.获取自动装配的组件 ...

  7. Spring Boot 自动装配流程

    Spring Boot 自动装配流程 本文以 mybatis-spring-boot-starter 为例简单分析 Spring Boot 的自动装配流程. Spring Boot 发现自动配置类 这 ...

  8. Spring Boot自动配置原理与实践(二)

    前言 在之前的博文(Spring Boot自动配置原理与实践(一))中,已经介绍了Spring boot的自动配置的相关原理与概念,本篇主要是对自动配置的实践,即自定义Starter,对原理与概念加深 ...

  9. Spring Boot自动配置原理、实战

    Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...

随机推荐

  1. Python:socket编程教程

    ocket是基于C/S架构的,也就是说进行socket网络编程,通常需要编写两个py文件,一个服务端,一个客户端. 首先,导入Python中的socket模块: import socket Pytho ...

  2. Java中Double类型数据比较大小

    方法一:转成字符串之后比较 如果要比较的两个double数据的字符串精度相等,可以将数据转换成string然后借助string的equals方法来间接实现比较两个double数据是否相等.注意这种方法 ...

  3. C语言动态输出等腰三角形

    C语言动态输出等腰三角形 题目要求:输入行数 打印出对应行数的等腰三角形,要求使用for循环嵌套. 思路 while语句写外层死循环 用于判断输出的数据: 分析: 最外层for,来控制最外层行数,存储 ...

  4. CMU15445 (Fall 2019) 之 Project#2 - Hash Table 详解

    前言 该实验要求实现一个基于线性探测法的哈希表,但是与直接放在内存中的哈希表不同的是,该实验假设哈希表非常大,无法整个放入内存中,因此需要将哈希表进行分割,将多个键值对放在一个 Page 中,然后搭配 ...

  5. Tapdata肖贝贝:实时数据引擎系列(三) - 流处理引擎对比

      摘要:本文将选取市面上一些流计算框架包括 Flink .Spark .Hazelcast,从场景需求出发,在核心功能.资源与性能.用户体验.框架完整性.维护性等方面展开分析和测评,剖析实时数据框架 ...

  6. 树莓派实战:微信机器人(itchat实现)

    背景 楼主有一台树莓派4B开发板(8G内存版),是目前的顶配机型.这一年来的业余时间,除了写Java.架构方面的文章,也陆续折腾了不少树莓派上的好玩小项目,在此新开一个树莓派实战的文章系列,分享给粉丝 ...

  7. Grid属性太多记不住?【Grid栅格布局可视化编辑器】直观易懂高效,拖拉拽,有手就行!

    手把手教你通过拖拉拽可视化的方式带你练习[Grid栅格布局]的各个属性,直观易懂!再也不愁记不住繁多的Grid属性了.整个过程在众触应用平台进行,不用手写一行CSS代码. grid-auto-flow ...

  8. day01 File类_Lambda

    File类 File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径) 使用File可以做到: 1:访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等 ...

  9. Solution -「Luogu 5170」类欧几里得算法

    推柿子大赛了属于是. 题目要求三个柿子,不妨分别记为: \[\begin {align} f (a, b, c, n) &= \sum \limits _{i = 0} ^{n} \lfloo ...

  10. 【Azure 应用服务】本地创建Azure Function Kafka Trigger 函数和Kafka output的HTTP Trigger函数实验

    问题描述 在上一篇博文(https://www.cnblogs.com/lulight/p/16525902.html)中,我们成功的以VM作为Kafka服务器运行,并且验证了从其他机器中远程访问.在 ...