Spring Boot自动装配代码详解
-
概述
- Spring Boot自动装配是其核心特性之一,它能够根据项目中添加的依赖自动配置Spring应用程序。通过自动装配,开发人员可以减少大量的配置工作,快速搭建起一个可用的Spring应用。
-
关键组件和注解
@SpringBootApplication
注解- 这是Spring Boot应用的主注解,它是一个组合注解,实际上包含了
@Configuration
、@EnableAutoConfiguration
和@ComponentScan
三个注解。 @Configuration
:表明这个类是一个配置类,用于定义Spring的Bean。在配置类中,可以通过@Bean
注解方法来创建和配置Bean实例。例如:@Configuration public class AppConfig {@Beanpublic MyService myService() {return new MyServiceImpl();} }
- 这里定义了一个名为
myService
的Bean,类型是MyService
,其实现是MyServiceImpl
。
- 这里定义了一个名为
@EnableAutoConfiguration
:这是自动装配的关键注解。它会启用Spring Boot的自动配置机制,告诉Spring Boot去根据项目的依赖和配置自动配置应用。它通过@Import
注解导入了AutoConfigurationImportSelector
类来实现自动配置的功能。@ComponentScan
:用于扫描指定包及其子包下的组件(如@Component
、@Service
、@Repository
、@Controller
等注解标记的类),将它们注册为Spring的Bean。默认情况下,它会扫描主应用类所在的包及其子包。例如,如果主应用类在com.example.myapp
包下,那么@ComponentScan
会扫描com.example.myapp
及其所有子包下的组件。
- 这是Spring Boot应用的主注解,它是一个组合注解,实际上包含了
AutoConfigurationImportSelector
类- 这个类是自动装配的核心实现类。它实现了
ImportSelector
接口,该接口的selectImports
方法用于返回要导入的配置类的全限定名数组。 - 在
AutoConfigurationImportSelector
中,selectImports
方法会从META - INF/spring.factories
文件中读取自动配置类的列表。它通过SpringFactoriesLoader.loadFactoryNames
方法来加载这些配置类,例如:public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
- 这里的
getAutoConfigurationEntry
方法会获取需要自动导入的配置类,这些配置类是根据项目中的依赖和条件来确定的。
- 这个类是自动装配的核心实现类。它实现了
-
META - INF/spring.factories
文件机制- 这是自动装配的重要配置文件。在Spring Boot的各个依赖中,都可以包含
META - INF/spring.factories
文件。 - 这个文件的格式是
key = value
的形式,其中一个关键的配置项是org.springframework.boot.autoconfigure.EnableAutoConfiguration
。它的值是一个自动配置类的列表,例如:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\// 其他自动配置类
- 当Spring Boot启动时,
AutoConfigurationImportSelector
会读取这些文件,找到所有的自动配置类。然后,根据条件注解(如@ConditionalOnClass
、@ConditionalOnMissingBean
等)来判断这些自动配置类是否应该被应用。 - 条件注解示例
@ConditionalOnClass
:这个注解用于判断某个类是否在类路径上。例如,DataSourceAutoConfiguration
中有如下注解:@Configuration @ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class}) public class DataSourceAutoConfiguration {// 配置内容 }
- 这表示只有当
DataSource
类和EmbeddedDatabaseType
类都在类路径上时,DataSourceAutoConfiguration
这个自动配置类才会被应用。这样可以确保只有在项目中添加了相关的数据源依赖时,才会进行数据源的自动配置。
- 这表示只有当
@ConditionalOnMissingBean
:用于判断某个类型的Bean是否不存在。例如,在某个自动配置类中定义一个方法来配置一个Bean:@Bean @ConditionalOnMissingBean public MyBean myBean() {return new MyBeanImpl(); }
- 这表示只有当容器中不存在
MyBean
类型的Bean时,才会创建并添加MyBeanImpl
这个Bean到容器中。
- 这表示只有当容器中不存在
- 这是自动装配的重要配置文件。在Spring Boot的各个依赖中,都可以包含
-
自动配置的过程
- Spring Boot应用启动时,首先会加载主应用类,由于
@SpringBootApplication
注解的存在,@Configuration
注解使得这个类被视为一个配置类,@ComponentScan
开始扫描组件。 - 同时,
@EnableAutoConfiguration
触发自动装配过程。AutoConfigurationImportSelector
从各个依赖的META - INF/spring.factories
文件中获取自动配置类列表。 - 然后,对于每个自动配置类,根据条件注解来检查是否满足应用条件。如果满足条件,就会将这个自动配置类加载到Spring容器中,自动配置类中的
@Bean
方法会被调用,创建和配置相应的Bean,从而完成自动装配的过程。
- Spring Boot应用启动时,首先会加载主应用类,由于
具体源码讲解
-
@SpringBootApplication
注解源码分析- 首先查看
@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 = AutoExcludeFilter.class) }) public class SpringBootApplication { }
- 可以看到它是一个组合注解,包含了
@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
。 @SpringBootConfiguration
:它实际上就是@Configuration
注解,用于标识这个类是一个配置类。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public class SpringBootConfiguration { }
@EnableAutoConfiguration
:这是自动装配的关键。它的源码如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public class EnableAutoConfiguration { }
- 其中
@Import(AutoConfigurationImportSelector.class)
是核心部分。这个AutoConfigurationImportSelector
类用于加载自动配置类。 @ComponentScan
:用于扫描组件,它有一些默认的扫描规则和可以自定义的过滤规则,如上述代码中的excludeFilters
,用于排除某些类型的组件扫描。
- 首先查看
-
AutoConfigurationImportSelector
源码分析AutoConfigurationImportSelector
实现了ImportSelector
接口,其中关键的方法是selectImports
:
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
- 这个方法首先检查自动配置是否启用。然后通过
AutoConfigurationMetadataLoader.loadMetadata
加载自动配置元数据,再通过getAutoConfigurationEntry
获取自动配置项。 - 深入
getAutoConfigurationEntry
方法:
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations);Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = filter(configurations, autoConfigurationMetadata);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions); }
- 在这里,
getCandidateConfigurations
方法用于获取候选的自动配置类列表,它会从META - INF/spring.factories
文件中读取相关配置:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, "No auto - configuration classes found in META - INF/spring.factories. If you " +"are using a custom packaging, make sure that file is correct.");return configurations; }
SpringFactoriesLoader.loadFactoryNames
方法会读取META - INF/spring.factories
文件,查找org.springframework.boot.autoconfigure.EnableAutoConfiguration
对应的配置类列表。
-
META - INF/spring.factories
文件读取源码分析SpringFactoriesLoader
类用于读取spring.factories
文件,关键方法是loadFactoryNames
:
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
- 它调用了
loadSpringFactories
方法:
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result!= null) {return result;}try {Enumeration<URL> urls = (classLoader!= null?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<Object, Object> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;} catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);} }
- 这个方法首先检查缓存中是否已经有读取的结果。如果没有,就通过
ClassLoader
获取META - INF/spring.factories
文件的URL
,然后将其内容读取到Properties
对象中。最后,将文件中的配置解析出来,以key - value
的形式存储在MultiValueMap
中,其中key
是配置项的类型(如org.springframework.boot.autoconfigure.EnableAutoConfiguration
),value
是对应的配置类列表。
-
条件注解的源码体现(以
@ConditionalOnClass
为例)@ConditionalOnClass
注解用于判断某个类是否在类路径上。它的实现基于Condition
接口。- 当Spring容器在处理自动配置类时,会检查条件注解。
@ConditionalOnClass
对应的Condition
实现类是OnClassCondition
。在自动配置类加载过程中,会调用OnClassCondition
的matches
方法来判断条件是否满足:
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 省略部分代码List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);if (onClasses!= null) {List<String> missing = filter(onClasses, ClassNameFilter.MISSING, context);if (!missing.isEmpty()) {return false;}}List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);if (onMissingClasses!= null) {List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, context);if (!present.isEmpty()) {return false;}}return true; }
- 这个方法会获取
@ConditionalOnClass
注解中指定的类列表,然后检查这些类是否在类路径上。如果有任何一个指定的类不存在,就返回false
,表示条件不满足,自动配置类不会被加载。通过这样的机制,Spring Boot可以根据类的存在与否来决定自动配置类的加载与否,实现智能的自动装配。
相关文章:
Spring Boot自动装配代码详解
概述 Spring Boot自动装配是其核心特性之一,它能够根据项目中添加的依赖自动配置Spring应用程序。通过自动装配,开发人员可以减少大量的配置工作,快速搭建起一个可用的Spring应用。 关键组件和注解 SpringBootApplication注解 这是Spring Bo…...

渗透测试-非寻常漏洞案例
声明 本文章所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法. 此文章不允许未经授权转发至除先知社区以外的其它平台!࿰…...
122. 买卖股票的最佳时机 II
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/?envTypestudy-plan-v2&envIdtop-interview-150问题分析: 和买卖股票的最佳时机I这题相比,区别就是可以买多只股票虽然同时只能持有一支,但是我们还是可以…...
Python爬虫入门指南:从零开始抓取数据
Python爬虫入门指南:从零开始抓取数据 引言 在大数据时代,数据是新的石油。而爬虫作为获取数据的重要手段,受到了越来越多的关注。Python作为一门强大的编程语言,其简洁易用的特性使得它成为爬虫开发的首选语言。本篇文章将带你…...

Android使用JAVA调用JNI原生C++方法
1.native-lib.cpp为要生成so库的源码文件 2.JNI函数声明说明 NewStringUTF函数会返回jstring JNI函数声明规则 3.JAVA中声明及调用JNI函数 声明: 调用 4.源码地址: gitgithub.com:tonyimax/UpdateTimeByThread.git...
ros常用命令记录
文章目录 1.基本2.rosbag2.1录制rosbag包2.2播放录制的ROS包 3.生命周期4.ROS启动,roslaunch5.ROS消息发布6.ROS消息后台打印监控 1.基本 ros2 topic list #查看话题列表2.rosbag 2.1录制rosbag包 ros2 bag record <topic_name> #记录单个主题消息 ros2 ba…...

UE5材质节点VertexNormalWs/PixelNormalWS
VertexNormalWs顶点法线方向,此节点可以做物体上积雪、青苔等效果 PixelNormalWS像素法线方向...

友元和运算符重载
1. 友元 可以把某些选定的函数看作类的“荣誉函数”,允许它们访问类对象中非公共的成员,就好像它们是类的成员一样,这种函数称为类的友元。友元可以访问类对象的任意成员。 1.1 友元函数 友元函数是一种定义在类外部的普通函数࿰…...

【数据库事务锁的类型:读锁/写锁、悲观锁/乐观锁、表锁/页锁/行锁】
数据库事务锁的类型:读锁/写锁、悲观锁/乐观锁、表锁/页锁/行锁 一、读锁/写锁1、锁定读 二、悲观锁/乐观锁2.1 悲观锁2.2 乐观锁 三、表锁/页锁/行锁3.1 表级别的S锁、X锁3.2 表级别的意向锁(intention lock) 一、读锁/写锁 对于数据库中并…...

【Motion Builder】配置c++插件开发环境
目录 准备环境构建官方案例另行构建经验分享附录 准备环境 安装Motion Builder 2024并破解安装Qt 5.15.2 截止至2024年12月19日,Qt的在线安装器的默认页面是没有5.15.2版本的。你需要:在“选择组件”界面,选择“Archive”,点击“…...

多线程访问FFmpegFrameGrabber.start方法阻塞问题
一、背景 项目集成网络摄像头实现直播功能需要用到ffmpeg处理rtmp视频流进行web端播放 通过网上资源找到大神的springboot项目实现了rtmp视频流转为http请求进行视频中转功能,其底层利用javacv的FFmpegFrameGrabber进行拉流、推流,进而实现了视频中转。 …...
MySQL使用记录
char和varchar varchar是可变长的,实际用多少它就占多少,和char不同,char规定多少它就会占多少 varchar的长度是字符个数,不管是数字、英文还是汉字,varchar(10)都可以存10个,而不会出现因为汉字占更多的字…...
【视觉SLAM:六、视觉里程计Ⅰ:特征点法】
视觉里程计(Visual Odometry, VO)是通过处理图像序列,估计摄像头在时间上的相对位姿变化的技术。它是视觉SLAM的重要组成部分之一,主要通过提取图像中的信息(如特征点或直接像素强度)来实现相机运动估计。以…...
Python 数据结构揭秘:栈与队列
栈(Stack) 定义 栈是一种后进先出(Last In First Out, LIFO)的数据结构。它类似于一个容器,只能在一端进行插入和删除操作。栈有两个主要的操作:push(入栈)和 pop(出栈…...

常见的框架漏洞
1.Thinkphp Thinkphp5x远程命令执行及getshell 搭建靶场 cd vulhub/thinkphp/5-rce docker-compose up -d 首页 漏洞根本源于 thinkphp/library/think/Request.php 中method方法可以进行变量覆盖,通过覆盖类的核心属性filter导致rce,其攻击点较为多&…...
在C++中实现一个能够捕获弹窗、检查内容并在满足条件时点击按钮的程序;使用python的方案
在C中实现一个能够捕获弹窗、检查内容并在满足条件时点击按钮的程序是相当复杂的,因为C本身并不直接提供高级的GUI自动化功能。通常,这样的任务会使用Windows API(如User32.dll中的函数)或者一些第三方库(如UIAutomati…...

《Vue3实战教程》26:Vue3Transition
如果您有疑问,请观看视频教程《Vue3实战教程》...
【架构设计(一)】常见的Java架构模式
常见的 Java 架构模式解析 在 Java 开发领域,选择合适的架构模式对于构建高效、可维护且能满足业务需求的软件系统至关重要。本文将深入探讨几种常见的 Java架构模式,包括单体架构与微服务架构、分层架构与微服务架构的对比,以及事件驱动架构…...
自定义有序Map
package cn.ziqirj.common.utils;import lombok.Getter; import lombok.Setter;import java.util.ArrayList; import java.util.List;/*** 模拟Map集合,key不可重复,按插入顺序排序* author zhangji** param <T>*/ public class CustomOrderlyMap&…...

Jenkins(持续集成与自动化部署)
Jenkins 是一个开源软件项目,是基于Java开发的一种持续集成工具。 官网:https://www.jenkins.io/ GitLab安装使用 安装前提:内存至少需要4G 官方网站:https://about.gitlab.com/ 安装文档:https://docs.gitlab.c…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...

windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...