springboot2.x基础教程:自动装配原理与条件注解源码分析

Spring Boot自动装配原理 创建自定义自动配置类需要遵循特定的模式。定义配置类:使用(或SpringBoot 3.x中的)注解标记配置类,并添加适当的条件注解。@Bean注册配置类:在项目的文件中添加以下内容:或在SpringBoot 3.x中使用绑定配置属性如果配置类需要外部属性,可以定义一个属性类并使用注解:@Component//...@Autowired//...自定义条件注解对于复杂的条件判断,可以创建自定义条件注解:@Override// 自定义条件判断逻辑// 自定义条件参数。 阅读详情

spring Boot采用约定优于配置的方式,大量的减少了配置文件的使用。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
当springboot启动的时候,默认在容器中注入许多AutoCongfigution类。在我们加入spring-boot-stareter-xx时,XXXAutoConfiguration类根据对应的条件,自动选择装配对应的Bean实例注入IOC容器中。

先说结论

  1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
  2. @EnableAutoConfiguration Import的AutoConfigurationImportSelector中代码最终调用SpringFactoriesLoader.loadSpringFactories扫描了Jar包的META-INF/spring.factories文件加载了大量的XXAutoConfiguration类
  3. AutoConfiguration类配合Conditonal注解与ConfigurationProperties配置类在特定条件下自动装配我们需要的Bean到IOC容器中。

注入AutoConfiguration类核心源码分析

SpringBoot的主启动类上需要加入@SpringBootApplication注解,我们看看该注解的源码。

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

实际是@EnableAutoConfigurtaion注解起作用。

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
	Class<?>[] exclude() default {};
	String[] excludeName() default {};

}

看到@Import注解是不是很熟悉,该注解作用见教程@Enable原理,主要能够导入下面3种情况中的Bean。

  1. 允许注入使用@Configuration注解的类
  2. 允许使用实现ImportSelectorj接口的类,注入selectImports返回的类
  3. 允许是实现了ImportBeanDefinitionRegistrar接口的类

AutoConfigurationImportSelector中selectImports源码

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

其中AutoConfigurationImportSelector.getAutoConfigurationEntry调用AutoConfigurationImportSelector.getCandidateConfigurations调用SpringFactoriesLoader.loadFactoryNames调用SpringFactoriesLoader.loadSpringFactories。

其中SpringFactoriesLoader.loadSpringFactories从指定的配置文件META-INF/spring.factories加载配置。

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

总结:

  1. @SpringBootApplication中@EnableAutoConfiguration注解最终调用SpringFactoriesLoader.loadSpringFactories,从classpath中搜寻所有的META-INF/spring.factories配置文件
  2. 并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

条件注解

在spring-boot-autoconfigure包在META-INF/spring.factories文件中autoconfiguration配置项一览。

image-20200909232847766

我们拿DataSourceAutoConfiguration源码分析,看看autoconfiguration类生效的条件。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@Conditional(EmbeddedDatabaseCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import(EmbeddedDataSourceConfiguration.class)
	protected static class EmbeddedDatabaseConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
			DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {

	}
	//省略....

}

在DataSourceAutoConfiguration类中,存在大量的@ConditionalXX条件注解,常见条件注解作用:

  1. @ConditionalOnBean:当SpringIoc容器内存在指定Bean的条件
  2. @ConditionalOnClass:当SpringIoc容器内存在指定Class的条件
  3. @ConditionalOnExpression:基于SpEL表达式作为判断条件
  4. @ConditionalOnJava:基于JVM版本作为判断条件
  5. @ConditionalOnJndi:在JNDI存在时查找指定的位置
  6. @ConditionalOnMissingBean:当SpringIoc容器内不存在指定Bean的条件
  7. @ConditionalOnMissingClass:当SpringIoc容器内不存在指定Class的条件
  8. @ConditionalOnNotWebApplication:当前项目不是Web项目的条件
  9. @ConditionalOnProperty:指定的属性是否有指定的值
  10. @ConditionalOnResource:类路径是否有指定的值
  11. @ConditionalOnSingleCandidate:当指定Bean在SpringIoc容器内只有一个,或者虽然有多个但是指定首选的Bean
  12. @ConditionalOnWebApplication:当前项目是Web项目的条件
  13. @EnableConfigurationProperties注解:使使用 @ConfigurationProperties 注解的类生效。
    我们可以看在DataSourceAutoConfiguration激活了DataSourceProperties配置,并且根据条件注解在不同情况下加载不同的数据源到IOC容器中。

千里之行,始于足下。这里是SpringBoot教程系列第十七篇,所有项目源码均可以在我的GitHub上面下载源码。觉得不错可以评论、点赞、转发3连。

Spring Data R2DBC API(Spring Data R2DBC 开发文档).CHM Spring Data R2DBC。 官网 Spring Data R2DBC API。 Spring Data R2DBC 开发文档。 立即下载

相关推荐

Flink项目基础配置指南

在大数据处理领域,Apache Flink凭借强大的实时流处理和批处理能力,成为众多开发者的首选工具。在日常工作中,开发Flink Jar任务是常见需求,但每次都需重复配置日志、梳理pom依赖、设置打包插件等,流程繁琐且易出错。为提升开发效率,减少重复劳动,将这些基础配置进行整理归纳十分必要。本文将围绕Flink项目的本地日志配置、pom依赖及插件配置展开详细介绍,为开发者提供一套可直接复用的基础配置方案,助力Flink项目高效开发。在Flink项目中,日志是了解任务运行状态、排查问题的重要依据。本地日志配

qq_42773076的博客 1210

SpringBoot参数封装问题

SpringBoot参数封装问题参数封装原因参数封装过程最终解决方案注意事项 参数封装 原因 最近在重构项目,需要对树接口进行重构,原先是通过字符串拼接,使用HttpClient客户端进行调用,现需改成openFeign客户端调用,因此,需要把有关树的参数封装为DTO的形式,方便调用。 参数封装过程 参数需要: http:/ip:port/tree?query[form]=xxx&query[userId]=xxx&page.sort[0].field=SHOW_ORDER&page

weixin_45785469的博客 723

解决Windows无法卸载补丁的实用方法

无法卸载Windows补丁可能是一个棘手的问题,但通过上述方法,你应该能够找到解决方案。无论是通过控制面板、命令提示符还是手动重置Windows更新组件,都有可能成功卸载问题补丁。如果所有方法都无效,系统还原将是一个值得尝试的备选方案。希望这篇文章能帮助你解决无法卸载补丁的问题。

mmoo_python的博客 1万+

r2dbc介绍 及 动态数据源实现方式

一、基本概念: 传统情况Java 使用 JDBC 来操作关系型数据库,而 JDBC 是阻塞的、同步的,即使使用线程池进行改善也是有限的。基于此,Spring官方(Pivotal)提出了R2DBC(Reactive Relational Database Connectivity)。R2DBC是一项API规范计划,它声明了一个反应式API,该方法将由数据库厂商实现以访问其关系数据库。 目前实现了R2DBC的数据库驱动有:H2、MariaDB、Microsoft SQL Server、MySQL 、jasy

wangqiso的博客 1万+

水文预报新手别怕!用Matlab 18小时搞定马斯京根法参数K和x(附完整代码)

本文详细介绍了如何使用Matlab在18小时内快速掌握水文预报中的马斯京根法参数K和x的求解方法。通过完整的代码示例和分步解析,帮助新手从理论到实践快速跨越,解决传统手工试算耗时耗力的问题,提升水文预报的效率和精度。

weixin_42573113的博客 256

在trae CN中使用conda环境(已解决)

Trae CN 是字节跳动于 2025 年 3 月 3 日发布的国内首个 AI 原生集成开发环境(AI IDE)123。

zwzscnds的博客 6937

SpringBoot 官方文档示例:(68)使用R2DBC操作Postgresql

boot

amadeus_liu2的博客 2402

WPT无线电能传输公式推导、编程计算、仿真验证全过程

主要分为5大模块,分别为无补偿,SS,SP,PP,PS,每个模块对应有公式推导,matlab编程计算相关参数以及将计算参数和仿真验证观察是否对应。采用matlab编程计算参数以及simulink仿真验证

zzhao2580的博客 7756

SpringBoot数据源——为什么平时默认线程池是Hikari

为什么平时默认线程池是Hikari?点开类,带你解读

运气不好努力来凑 1855

Elasticsearch连接中断:深入解析Connection reset by peer问题及优化策略

本文深入解析Elasticsearch连接中断问题,特别是Connection reset by peer错误的成因与解决方案。从TCP层的心跳机制到客户端与服务端的配置差异,详细介绍了网络不稳定、防火墙拦截等常见原因,并提供了六种优化策略,包括KeepAlive调整、TCP参数调优和智能重试机制等,帮助提升Elasticsearch连接的稳定性。

weixin_42546392的博客 410

【AI智能体】Dify 搭建数据分析应用实战操作详解

Dify 搭建数据分析应用实战详解

congge 7296

Springboot 整合 r2dbc

R2DBC的诞生为了非阻塞的应用栈, 使用很少的线程可以处理大量的并发同时减少硬件资源。大量的应用还是使用的关系型数据库,然而很多 NoSQL 数据提供了响应式客户端,并不是所有的项目都适合迁移到 NoSQL。因此,R2DBC 应运而生。对于 R2DBC 的驱动实例,Spring 支持基于Java 的@Connfiguration的配置。R2DBC 是一个 API 规范的倡议,声明对于访问关系型数据库驱动实现了一些响应式的API。自动实现 Reposity 接口,包含支持自定义的查询方法。

专注Java(全栈)应用开发,求知若渴,虚心若愚,talk is cheap, show me the code. 1521

【史上最全面esp32教程】网络篇和tcp/ip的使用

ESP32史上最全面wifi和tcp/ip连接及示例程序

m0_62599305的博客 9522

SpringBoot自动装配原理,这一篇就够了!

有关SpringBoot自动装配原理,你需要知道的一切。

CC_且听风吟丶的博客 8万+

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

spring boot 注解_springboot2x基础教程:自动装配原理与条件注解

spring Boot采用约定优于配置的方式,大量的减少了配置文件的使用。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。当springboot启动的时候,默认在容器中注入许多AutoCongfigution类。在我们加入spring-boot-stareter-xx时,XXXAutoConfiguration类根据对应的条件,自动选择装配对应的...

weixin_39559015的博客 104

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

SpringBoot自动装配原理分析

若需自定义条件(如不依赖注解),可直接在中添加:properties 复制 com.example.RedisAutoConfig=org.springframework.boot.autoconfigure.condition.ConditionalOnClass=org.springframework.data.redis.core.RedisTemplate通过,Spring Boot 实现了 ​按条件动态加载配置类​ 的核心逻辑。开发者只需关注条件本身,无需手动实现复杂的过滤代码。

2401_89221867的博客 959

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

SpringBoot2.x 教程:自动装配原理与条件注解详解

spring Boot采用约定优于配置的方式,大量的减少了配置文件的使用。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。 当springboot启动的时候,默认在容器中注入许多AutoCongfigution类。在我们加入spring-boot-stareter-xx时,XXXAutoConfiguration类根据对应的条件,自动选择装配对应的Bean实例注入IOC容器中。 先说结论 SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoCo.

Java_Jishu的博客 201

《SpringBoot系列十三》:图文精讲@Conditional条件装配实现原理

1、@Conditional条件装配实现原理? 2、什么时候进行条件装配? 3、条件装配的两个阶段介绍一下? 4、@ConditionalOnClass实现原理? 5、@ConditionalOnBean实现原理?

健身变秃,coding变强 4894

SpringBoot源码分析(二)之自动装配demo

SpringBoot源码分析(二)之自动装配 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录SpringBoot源码分析(二)之自动装配前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍

zhang_didi的博客 2417

【5w字】SpringBoot源码分析

SpringBoot源码分析,从启动类入手,分析SpringBoot的启动流程和SpringBoot自动装配原理以及SPI机制拓展,达到可以开发starter中间件的水平。

Javaer 3249

Springboot自动装配工作原理-注解自动装配(注解,自定义starter启动器)

Springboot自动装配工作原理-注解自动装配(注解,自定义starter启动器)Springboot自动装配工作原理1.1 Springboot自动装配原理是什么1.1.1 Springboot帮我们做了什么1.1.2 关于Springboot起步依赖 Springboot自动装配工作原理 使用过springboot的同学应该已经知道 springboot默认配置了很多框架的使用方式 帮我们大大简化了项目初始搭建以及开发过程。 接下来 我们就一步步分析springboot的启动过程 分析sp

m0_46690280的博客 1358

SpringBoot自动装配原理深度剖析,看完再也不怕面试官问了!

摘要:本文深入剖析Spring Boot自动装配原理,解析@SpringBootApplication的三合一结构,重点讲解@EnableAutoConfiguration如何通过AutoConfigurationImportSelector加载候选配置类。文章详细介绍了Spring Boot 3.x的配置加载机制,从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports读取配置,并利用条件注解实现按需

夜雨的博客 1136

springboot3自动装配机制原理源码分析

导入starter、修改配置文件,就能修改底层行为

Ostkakah的博客 1036

Springboot类自动装配原理探究

在最早的时候,我们运行代码时,如果需要某个对象,那么就需要我们自己去new对象,这很麻烦。可能你并未感知到,那么举个例子说明一下,请看下面代码System.out.println("早上了,人要吃饭");System.out.println("中午了,人要吃饭");System.out.println("晚上了,人要吃饭");System.out.println("早上了,狗狗要吃饭");System.out.println("中午了,狗狗要吃饭");

m0_46212021的博客 930

springboot2.x基础教程:@Enable*原理

上一篇springboot2.x基础教程:@Async开启异步任务我们使用了@EnableAsync注解来启用异步执行。 SpringBoot框架中@Enable*注解有很多例如:@EnableAspectJAutoProxy、@EnableCaching、@EnableAutoConfiguration、@EnableSwagger2这一章讲讲它背后的原理。 本文导航几个典型的@Enable*注解@EnableScheduling@EnableAsync@EnableAspectJAutoProxy@.

编程之家出品 249
上一篇: Java Jar源码反编译工具那家强
下一篇: springboot2.x基础教程:动手制作一个starter包
程序员众推
博客等级 码龄10年 8粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员众推

谢谢老铁鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值