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()这个方法具体实现:
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()
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
首先判断自动配置功能是否开启。
isEnabled()方法会检查属性@EnableAutofiguration注解的enabled属性(默认为true),也可能结合其他全局开关。如果返回false的,表示关闭自动配置,直接返回空结果。
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
从注解元数据AnnotationMetadata中提取@EnableAutoConfiguration的属性信息。
@EnableAutoConfiguration有exclude,excludeName等属性(用于指定需要排除的自动配置类),getAttributes()会将这些属性解析为AnnotationAttribute对象,方便后续处理。
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等。
configurations = this.removeDuplicates(configurations);
对候选配置类去重,避免同一个配置类被多次加载。
如果多个 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件定义了同一个自动配置类,这里确保最终只保留一个。
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
收集所有需要排除的自动配置类
@EnableAutoConfiguration注解的exclude属性(直接指定类)或者是excludeName属性指定类名。还可以通过配置文件application.yaml中通过spring.autoconfigure.exclude配置的类。
this.checkExcludedClasses(configurations, exclusions);
检查需要排除的类是否确实存在于候选配置类中。
如果用户排除了一个不存在的自动配置类(如拼写错误),这里会抛出异常(illegalArgumentException),提前暴露配置错误。
configurations.removeAll(exclusions);
将需要排除的类从候选配置类列表中彻底移除。
被排除的类不会被Spring容器加载,实现了“自定义排除不需要的自动配置”的功能。
configurations = this.getConfigurationClassFilter().filter(configurations);
通过条件过滤器筛选出符合当前环境的配置类。
过滤器会检查每个候选配置类上的@Conditional系类注解(如@ConditionalOnClass,@ConditionalOnMissingBean等),只有满足所有条件的配置类才会被保留。
this.fireAutoConfigurationImportEvents(configurations, exclusions);
触发自动配置导入事件,通知相关监听器(AutoConfigurationImportListenter)。
允许外部自动配置进行扩展(如日志记录,额外处理等)。
return new AutoConfigurationEntry(configurations, exclusions);
将筛选后的有效配置类和排除类封装为AutoConfigurationEntry对象并返回。
Spring 容器会根据该结果,将configurations中的类作为类加载,从而完成自动装配。
总结:
1.先检查开关,确保自动配置启用
2.加载预定义的候选配置类
3.处理去重和排除,移除不需要的类
4.通过@Conditional注解筛选符合当前环境的类
5.发布事件并返回结果
最终,筛选后的配置类会被Spring容器加载,其内部定义的@Bean方法会生成相应的Bean,实现自动配置的效果。