news 2026/7/16 14:56:22

SpringBoot自动配置原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot自动配置原理

问题引入

SpringBoot最核心的一个东西就是自动配置,自动配置的原理是什么?

我们知道Spring最开始是通过xml文件配置,来告诉Spring要创建哪些类、哪些Bean。

后来进化为可以通过注解来配置,这样就不用去写xml文件了,只需要告诉Spring去扫描哪些包就可以了。

那么问题来了,如果是一个三方服务框架包,我怎么知道要去扫描哪些包呢?

很多时候我们还是只能通过@Bean的方式去创建,一些复杂的服务可能需要创建很多Bean,我们怎么知道要创建哪些Bean呢?这些Bean的关联关系又是怎样的呢?

用起来太麻烦了,很多时候,我们并不想知道实现的具体细节,我们只希望拿来就能用,怎么办呢?

于是:SpringBoot来了,它可以自动完成配置,创建并注入需要的Bean,不需要我们自己去创建了,若有的创建Bean的工作都由提供服务的服务者去创建,他们自己实现的,当然更清楚怎么用,怎么创建系列Bean。

那么,问题又来了,SpringBoot是怎么做到自动配置的呢?

答案是:类Java SPI机制。

Java SPI机制

一个好的语言、框架设计时候一定要考虑好扩展,做好抽象层。

例如Java的数据库驱动就是一个好的例子,我们使用的都是java.sql包下的抽象层接口,根本不用关心是哪种数据库,实现细节是什么。

一个不好的例子,就是Java的日志功能,所以抽象做得更好的slf4j-api基本就成了共用接口标准。

当然,技术在不断发展,很多时候,我们再设计的时候并不能考虑到那么多,例如响应式编程,那也是发展了很多年,才有projectreactor

Java的数据库驱动为什么能让我们不用关心具体实现呢,答案就是:SPI(Service Provider Interface)。

Java SPI核心类是:java.util.ServiceLoader

它会去扫描classpath下的META-INF/services目录下的文件,文件名是抽象层的全限定名,例如java.sql.Driver,文件内容是服务提供的具体实现类。

如:com.mysql.cj.jdbc.Driver

Java SPI Druid Driver

@EnableAutoConfiguration

Java SPI的核心类是ServiceLoader,SpringBoot自动配置的核心类是@EnableAutoConfiguration。

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

EnableAutoConfiguration它通过@Import(AutoConfigurationImportSelector.class)自动装配了AutoConfigurationImportSelector类。

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { }

AutoConfigurationImportSelector实现了DeferredImportSelector接口,DeferredImportSelector又实现了ImportSelector。

ImportSelector#selectImports就可以告诉Spring这些类需要被导入。

那AutoConfigurationImportSelector会去哪里找需要自动装配的类呢?

顺着接口selectImports找呗,有兴趣可以自己去跟源码,这里简单总结一下:

  1. ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
  2. 找的是AutoConfiguration类
  3. META-INF/spring/要找的类的全限定名称.imports文件
  4. 所以:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  5. 上面的文件配置的类,每行一个全部导入

还有一个ImportAutoConfigurationImportSelector,是处理ImportAutoConfiguration。

org.springframework.boot.autoconfigure.AutoConfiguration.imports

除了直接导入的,还有通过org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames导入,找的是META-INF/spring.factories文件。

spring.factories这个文件中的内容类似properties,是key-value形式,key是接口全限定名,value是具体实现类全限定名,多个逗号分隔。

spring.factories

对于自动导入来说,具体的接口是org.springframework.boot.autoconfigure.EnableAutoConfiguration。

例如:

@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class}) public class DruidDataSourceAutoConfigure {}

对过对于EnableAutoConfiguration,还是推荐使用新的规范,仍在META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,这样不用配置key,也不用考虑多行的问题,直接每行一个就行。

实现自己的EnableMyAutoConfiguration

知道了原理,我们可以动手实现一个我们自己的EnableMyAutoConfiguration。

首先是Enable注解:

import org.springframework.context.annotation.Import; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(MyAutoConfigurationImportSelector.class) public @interface EnableMyAutoConfiguration { }

然后是,我们需要处理什么注解呢?我们自定义的MyAutoConfiguration

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAutoConfiguration { }

接下来,我们需要一个DeferredImportSelector来加载配置的MyAutoConfiguration类。

import org.springframework.boot.context.annotation.ImportCandidates; import org.springframework.context.annotation.DeferredImportSelector; import org.springframework.core.type.AnnotationMetadata; import java.util.List; public class MyAutoConfigurationImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { List<String> configurations = ImportCandidates.load(MyAutoConfiguration.class, this.getClass().getClassLoader()) .getCandidates(); return configurations.toArray(new String[0]); } }

使用了@MyAutoConfiguration的配置类:

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; @MyAutoConfiguration @Import(BzClass.class) public class ConfigurationA { @Bean public String name(){ return "ConfigurationA"; } }

配置类中导入了具体的业务类:

public class BzClass { }

然后我们把配置类vip.oschool.custom.ConfigurationA,配置到META-INF\spring\vip.oschool.custom.MyAutoConfiguration.imports文件中。

然后,来一个启动类:

import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.support.GenericApplicationContext; @EnableMyAutoConfiguration public class Main { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("main", Main.class); // ConfigurationClassPostProcessor处理DeferredImportSelector context.registerBean(ConfigurationClassPostProcessor.class); context.refresh(); for (String beanName : context.getBeanDefinitionNames()) { System.out.println(beanName); } } }

手动实现自动加载

结果,我们可以看到,所有的配置类都被加载了。

starter

知道了自动配置原理,再来看starter就想吃饭喝水一样简单了。

通常我们自己的state人的artifactId是xxxx-spring-boot-starter,spring自己的stater是spring-boot-starter-xxxx

druid-spring-boot-starter就是把配置类添加到了spring.factories

druid自动配置实现

DruidDataSourceAutoConfigure创建了DruidDataSourceWrapper,又通过@Import导入DruidSpringAopConfiguration等实际业务类。

所以,我们什么都不用管,只需要把druid-spring-boot-starter添加入依赖就可以用了,因为DruidSpringAopConfiguration都帮我们创建好了。

当然,关联的依赖也在druid-spring-boot-starter的pom.xml中导入了。

还有一些更符合Spring模式的,例如,会单独有一个autoconfigure项目来管理自动配置。

自动配置的类配置在META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 4:50:56

创客匠人实践录:用AI赋能教育,让老师回归“真正的教学”

在数字化浪潮中&#xff0c;教育行业正经历一场深刻的效率革命。许多老师却感到困惑&#xff1a;每天忙于回复消息、重复答疑、整理资料&#xff0c;真正用于备课、研发、与学生深度交流的时间反而越来越少。技术到底是在帮助我们&#xff0c;还是在消耗我们&#xff1f;创客匠…

作者头像 李华
网站建设 2026/7/12 2:25:45

程序员必备:AI大模型(LLM)完整学习路线图+640份行业报告合集_2026最全面的AI大模型学习路线

本文为AI大模型学习者提供从基础知识到实践项目的完整学习路线&#xff0c;涵盖线性代数、Python编程、深度学习及预训练模型研究等内容。针对LLM学习资源稀缺问题&#xff0c;作者分享了系统梳理的L1-L7学习路线图和640套AI大模型报告合集&#xff0c;帮助小白降低自学门槛&am…

作者头像 李华
网站建设 2026/7/12 2:31:25

从零掌握多模态知识编辑:MMQAKE基准与Hybrid-DMKG框架实战指南

本文介绍了MMQAKE&#xff0c;首个针对多模态多跳问答的知识编辑基准&#xff0c;评估中间推理步骤质量和视觉改写鲁棒性。研究提出Hybrid-DMKG混合推理框架&#xff0c;基于动态多模态知识图谱实现精准多跳推理&#xff0c;结合符号关系遍历和检索增强生成两条路径&#xff0c…

作者头像 李华
网站建设 2026/7/16 8:04:51

【珍藏版】大模型系统学习指南:零基础到实战,助你快速成为AI工程师_2025最新AI大模型学习路线

文章提供了系统学习大模型的完整路线图&#xff0c;从数学基础、编程能力开始&#xff0c;逐步过渡到机器学习、深度学习&#xff0c;最终深入大模型技术。内容包括理论基础、实践项目、学习资源和社区参与。文章强调系统学习的重要性&#xff0c;避免零散学习&#xff0c;并提…

作者头像 李华
网站建设 2026/7/6 11:38:15

AI时代新纪元:2026年Geo优化的三大核心破局点

随着AI搜索&#xff08;如Google AI Overviews&#xff09;的普及&#xff0c;传统搜索引擎的流量正在被AI聊天机器人和虚拟代理所分流。Gartner预测&#xff0c;到2026年&#xff0c;传统搜索量将下降25% [1]。面对这一颠覆性变革&#xff0c;Geo优化&#xff08;Generative E…

作者头像 李华
网站建设 2026/7/15 0:10:35

混合精度训练实战:AMP在PyTorch中的应用

混合精度训练实战&#xff1a;AMP在PyTorch中的应用 在当今深度学习模型动辄上百亿参数的背景下&#xff0c;训练效率和显存占用已成为制约研发迭代速度的关键瓶颈。尤其是在使用Transformer架构进行大语言模型或视觉任务时&#xff0c;FP32单精度训练不仅对GPU显存提出极高要求…

作者头像 李华