SpringBoot自动装配原理

SpringBoot的自动装配是其核心特性之一,他简化了Spring应用的配置流程,实现了"约定大于配置"的理念。其核心原理可以概括为:通过特定的注解和配置文件,自动识别并加载符合条件的Bean到Spring容器中。

1.核心注解:@SpringBootApplication

自动装配的入口是主类上的@SpringBootApplication注解,它是一个符合注解,包含三个关键注解:

  • @SpringBootConfiguration:标记当前类为配置类(本质上是@Configuration的派生注解)
  • @ComponentScan:扫描当前包及其子包下的@Component,@Service等注解的类,注册为Bean。
  • @EnableAutoConfiguration:开启自动配置的核心注解,也是自动装配的关键。

2.@EnableAutoConfiguration的作用

当我们点进去这个核心注解的时候:

EnableAutoConfiguration 注解实现自动装配机制的时候,主要依赖于这个**@Import({AutoConfigurationImportSelector.class})** ,通过import的导入到AutoConfigurationImportSelector类,该类负责筛选并导入需要自动装配的类 。其中这个类的话实现自动装配依赖于**selectImports()**这个方法。

这个方法通过在内部调用getAutoConfigurationEntry方法来实现自动装配。

getCandidateConfigurations()这个方法会告诉要想将没有spingbootapplication注解启动的类,但是想让spring帮助我们进行注册Bean需要将类的全限定名加到某个文件中。

getCandidateConfigurations()这个方法具体实现:

java 复制代码
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).getCandidates();
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

也就是将需要注册的类全限定名写入到这个文件中。

举一个例子:

我们在另外一个工程里面封装了redis的一些方法以及redis的相关配置。希望能够在外部中引用RedisService这个对象。但是这个工程中并没有springbootapplication启动注解。所以将这个类的全限定名写入到以上这个文件中。

有两点需要进行注意:

一是一般这个文件创建在resources这个目录下,META-INF和spring这是两个目录,先创建META-INF目录再创建spring目录。同时在创建的时候需要打开一个东西。

把compact给取消掉。是因为在勾选上的话,创建的话不容易看出这是一个二级目录,我们想要的效果就是达到以下图片的效果。

3.详细解读getAutoConfigurationEntry()

java 复制代码
if (!this.isEnabled(annotationMetadata)) {
    return EMPTY_ENTRY;
}

首先判断自动配置功能是否开启。

isEnabled()方法会检查属性@EnableAutofiguration注解的enabled属性(默认为true),也可能结合其他全局开关。如果返回false的,表示关闭自动配置,直接返回空结果。

java 复制代码
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

从注解元数据AnnotationMetadata中提取@EnableAutoConfiguration的属性信息。

@EnableAutoConfiguration有exclude,excludeName等属性(用于指定需要排除的自动配置类),getAttributes()会将这些属性解析为AnnotationAttribute对象,方便后续处理。

java 复制代码
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

获取所有候选自动配置类的全限定名

getCandidateConfigurations()方法会读取类路径下 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,以org.springframework.boot.autoconfigure.EnableAutoConfiguration为key的所有值(这些值就是Spring Boot预定义的自动配置类,如WebMvcAutConfiguration等。

java 复制代码
configurations = this.removeDuplicates(configurations);

对候选配置类去重,避免同一个配置类被多次加载。

如果多个 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件定义了同一个自动配置类,这里确保最终只保留一个。

java 复制代码
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);

收集所有需要排除的自动配置类

@EnableAutoConfiguration注解的exclude属性(直接指定类)或者是excludeName属性指定类名。还可以通过配置文件application.yaml中通过spring.autoconfigure.exclude配置的类。

java 复制代码
this.checkExcludedClasses(configurations, exclusions);

检查需要排除的类是否确实存在于候选配置类中。

如果用户排除了一个不存在的自动配置类(如拼写错误),这里会抛出异常(illegalArgumentException),提前暴露配置错误。

java 复制代码
configurations.removeAll(exclusions);

将需要排除的类从候选配置类列表中彻底移除。

被排除的类不会被Spring容器加载,实现了"自定义排除不需要的自动配置"的功能。

java 复制代码
configurations = this.getConfigurationClassFilter().filter(configurations);

通过条件过滤器筛选出符合当前环境的配置类。

过滤器会检查每个候选配置类上的@Conditional系类注解(如@ConditionalOnClass,@ConditionalOnMissingBean等),只有满足所有条件的配置类才会被保留。

java 复制代码
this.fireAutoConfigurationImportEvents(configurations, exclusions);

触发自动配置导入事件,通知相关监听器(AutoConfigurationImportListenter)。

允许外部自动配置进行扩展(如日志记录,额外处理等)。

java 复制代码
return new AutoConfigurationEntry(configurations, exclusions);

将筛选后的有效配置类和排除类封装为AutoConfigurationEntry对象并返回。

Spring 容器会根据该结果,将configurations中的类作为类加载,从而完成自动装配。

总结:

1.先检查开关,确保自动配置启用

2.加载预定义的候选配置类

3.处理去重和排除,移除不需要的类

4.通过@Conditional注解筛选符合当前环境的类

5.发布事件并返回结果

最终,筛选后的配置类会被Spring容器加载,其内部定义的@Bean方法会生成相应的Bean,实现自动配置的效果。

相关推荐
Javatutouhouduan7 小时前
2026Java面试的正确打开方式!
java·高并发·java面试·java面试题·后端开发·java编程·java八股文
JAVA面经实录9177 小时前
Java初级最终完整版学习路线图
java·spring·eclipse·maven
Cat_Rocky8 小时前
k8s-持久化存储,粗浅学习
java·学习·kubernetes
知识领航员8 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
释怀°Believe9 小时前
Spring解析
java·后端·spring
ooseabiscuit9 小时前
Laravel4.x:现代PHP框架的奠基之作
java·开发语言·php
小新同学^O^10 小时前
简单学习 --> Spring事务
数据库·学习·spring
节奏昂10 小时前
【一份基础软件的下载地址和安装地址】
java
没什么本事10 小时前
关于C# panel 添加lable问题 -- 明确X和Y 位置错误
android·java·c#
dhashdoia10 小时前
GPT-5.5 代码开发实战:Codex与Browser Use深度集成与星链4SAPI优化方案
java·数据库·人工智能·gpt·架构