SpringBoot自动装配原理、条件注解及封装Starter

news/2024/11/29 9:59:27/

1.什么是 SpringBoot 自动装配?

我们现在提到自动装配的时候,一般会和Spring Boot联系在一起。但是实际上SpringFramework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。
SpringBoot 定义了一套接口规范:
SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。
没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。

<dependency>     <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId> 
</dependency> 

引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。

2.SpringBoot 是如何实现自动装配的?

依赖SpringBoot的核心注解实现 @SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {xxxx
}

其中@EnableAutoConfiguration 是实现自动装配的重要注解,我们以这个注解入手。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
xxx
}

可以看到自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector
那我们继续分析下AutoConfigurationImportSelector 类到底做了什么?
在这里插入图片描述

AutoConfigurationImportSelector:加载自动装配类

可以看到他是实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。

public String[] selectImports(AnnotationMetadata annotationMetadata) {// 判断自动装配开关是否打开 默认是开启if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 获取获取所有需要装配的beanAutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

我们在继续看getAutoConfigurationEntry 方法是如何获取装配bean的

/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;
}
// 获取EnableAutoConfiguration注解中的 exclude 和 excludeName。
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取装配Bean
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 过滤重复bean
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
// 移除需要排除的bean
configurations.removeAll(exclusions);
// 根据AutoConfigurationImportFilter的match方法来判断是否符合OnBeanCondition,OnClassCondition,OnWebApplicationCondition 过滤bean
configurations = getConfigurationClassFilter().filter(configurations);
// 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

其中getCandidateConfigurationsgetConfigurationClassFilter().filter 方法为核心
getCandidateConfigurations 获取配置bean ,如图所示
在这里插入图片描述
主要调用 org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames
再调用 org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories如图所示
其原理就是读取META-INF/spring.factories文件的的URL
在这里插入图片描述
getConfigurationClassFilter().filter 方法用于根据AutoConfigurationImportFilter的match方法来判断是否符合OnBeanCondition,OnClassCondition,OnWebApplicationCondition 过滤bean 如图所示
在这里插入图片描述
最后,总结下SpringBoot自动配置的原理,主要做了以下事情:

  1. spring.factories配置文件中加载自动配置类,利用org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories 方法实现
  2. 加载的自动配置类中排除掉@EnableAutoConfiguration注解的exclude属性指定的自动配置类;
  3. 再用AutoConfigurationImportFilter接口去过滤自动配置类是否符合其标注注解
    OnBeanCondition(如:ConditionalOnBean、ConditionalOnMissingBean)、OnClassCondition(如:ConditionalOnClass、ConditionalOnMissingClass)、OnWebApplicationCondition(如ConditionalOnWebApplication、ConditionalOnNotWebApplication)的条件,若都符合的话则返回匹配结果;
  4. 触发AutoConfigurationImportEvent事件
  5. 最后spring再将最后筛选后的自动配置类导入IOC容器中

拓展
1.条件注解
@ConditionalOnBean:当容器里有指定 Bean 的条件下
@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
@ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
@ConditionalOnClass:当类路径下有指定类的条件下
@ConditionalOnMissingClass:当类路径下没有指定类的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnExpression:基于 SpEL 表达式作为判断条件
@ConditionalOnJava:基于 Java 版本作为判断条件
@ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
@ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
@ConditionalOnWebApplication:当前项目是 Web 项 目的条件下
2.控制自动装配顺序注解
@AutoConfigureOrder
@AutoConfigureBefore
@AutoConfigureAfter
@AutoConfiguration(after = xx.class, before = xx.class)
@AutoConfigureOrder 此需要制定自定配置的顺序时,可以用 @AutoConfigureOrder ,表示绝对顺序(数字越小,优先顺序越高)。
@AutoConfigureBefore@AutoConfigureAfter 控制应用配置类的相对顺序。
具体顺序如下:

  1. 根据类名按照字母表递增排序
  2. 根据 @AutoConfigureOrder value 值(默认:0)递增排序
  3. 根据 @AutoConfigureBefore@AutoConfigureAfter 调整排序
    AutoConfigurationSorter 类是具体实现排序的逻辑

3.Starter编写

在这里插入图片描述在这里插入图片描述


http://www.ppmy.cn/news/30348.html

相关文章

顺序表以及链表的应用及区别(包含OJ讲解)

前面我已经发过怎么实现链表以及顺序表&#xff0c;今天大概的总结一下。 顺序表&#xff1a; 1.能够随时的存取&#xff0c;比较方便。 2.插入删除时&#xff0c;需要挪动数据&#xff0c;比较麻烦&#xff0c;因为是连续存储。 3.存储密度相对于链表来说是比较高的&#…

深度剖析C语言符号篇

致前行的人&#xff1a; 人生像攀登一座山&#xff0c;而找寻出路&#xff0c;却是一种学习的过程&#xff0c;我们应当在这过程中&#xff0c;学习稳定冷静&#xff0c;学习如何从慌乱中找到生机。 目录 1.注释符号&#xff1a; 2.续接符和转义符&#xff1a; 3.回车与换行…

文件服务设计

一、需求背景 文件的上传、下载功能是软件系统常见的功能&#xff0c;包括上传文件、下载文件、查看文件等。例如&#xff1a;电商系统中需要上传商品的图片、广告视频&#xff0c;办公系统中上传附件&#xff0c;社交类系统中上传用户头像等等。文件上传下载大致流程为&#…

【SPSS】多因素方差分析详细操作教程(附案例实战)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

位图/布隆过滤器/海量数据处理方式

位图 位图的概念 所谓位图&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于海量数据&#xff0c;数据无重复的场景。通常是用来判断某个数据存不存在的。 直接来看问题&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0…

linux系统防火墙开放端口

linux系统防火墙开放端口 在外部访问CentOS中部署应用时&#xff0c;需要通过防火墙管理软件,开端口,或者直接关闭防火墙进行解决(不建议) 加粗样式 常用命令&#xff1a; systemctl start firewalld #启动 systemctl stop firewalld #停止 systemctl status firewalld #查看…

【编程基础之Python】10、Python中的运算符

【编程基础之Python】10、Python中的运算符Python中的运算符算术运算符赋值运算符比较运算符逻辑运算符位运算符成员运算符身份运算符运算符优先级运算符总结Python中的运算符 Python是一门非常流行的编程语言&#xff0c;它支持各种运算符来执行各种操作。这篇文章将详细介绍…

嵌入式系统硬件设计与实践(开发过程)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 如果把电路设计看成是画板子的&#xff0c;这本身其实是狭隘了。嵌入式硬件设计其实是嵌入式系统中很重要的一个部分。里面软件做的什么样&#xf…