一、引入
SpringBoot以其强大的自动装配功能简化了应用搭建的复杂性,让开发者能够更高效地构建应用。那么,SpringBoot是如何实现这种“智能配置”的呢?本文将深入探讨SpringBoot的自动装配原理,并且探讨为什么当多模块下,需要使用其他模块时需要配置META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(SpringBoot2.7以前需要配置META-INF/spring.factories)?
二、流程图
三源码解读
3.1启动类一般是这样的
@SpringBootApplication
@MapperScan("cn.zc.system.mapper")//本行具体后续会讲解,先主要讲解SpringBootApplication
public class OjSystemApplication {
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(OjSystemApplication.class, args);
}
}
3.2 @SpringBootApplication注解: 这个注解是一个复合注解,它包括了@EnableAutoConfiguration,而@EnableAutoConfiguration又导入了AutoConfigurationImportSelector类。 本文我们主要讲下自动配置,关注@EnableAutoConfiguration这个注解
......
@SpringBootConfiguration
@EnableAutoConfiguration
.....
public @interface SpringBootApplication {
}
3.3 @EnableAutoConfiguration 常用于启用自动配置功能。它会根据类路径中的依赖和配置文件中的设置,自动配置 Spring 应用的基础设施,比如数据源、视图解析器等。
.....
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
.....
public @interface EnableAutoConfiguration {
}
重点便是这两个注解,我们接下来详细对这两个注解进行解析
-
@AutoConfigurationPackage 作用:自动将当前包及其子包注册为 Spring 的组件扫描包。这样,Spring 会自动扫描这些包中的组件并加载到应用上下文中。
-
@Import({AutoConfigurationImportSelector.class}) 作用:自动加载和注册配置类。
3.3.1 @Import({AutoConfigurationPackages.Registrar.class}) 中核心的代码:
//方法的作用功能:给容器中批量导入一些组件
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取到所有需要导入到容器中的配置类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 去重
configurations = this.removeDuplicates(configurations);
// 获取需要排除的列表
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 移除需要排除的数据
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 获取配置过滤器
configurations = this.getConfigurationClassFilter().filter(configurations);
// 触发导入自动配置事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回自动配置对象
return new AutoConfigurationEntry(configurations, exclusions);
}
}
让我们追进 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
注意!接下来,得到所有需要设置为Bean的类!
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
String location = String.format("META-INF/spring/%s.imports", annotation.getName());
Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
List<String> importCandidates = new ArrayList();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
importCandidates.addAll(readCandidateConfigurations(url));
}
return new ImportCandidates(importCandidates);
}
这是引入的jar包需要的bean
这是其他模块的路径,根据
3.3.2
@AutoConfigurationPackage
4、使用注意事项
虽然SpringBoot的自动装配功能强大且方便,但在使用时还是需要注意以下几点:
避免自动配置冲突:有时候,自动配置可能会与你的手动配置冲突。例如,如果你在配置文件中定义了一个DataSource Bean,而SpringBoot又尝试自动配置一个DataSource Bean,这可能会导致冲突。此时,你可以使用@Primary注解来指定优先使用的Bean,或者使用@EnableAutoConfiguration(exclude={...}来排除某些自动配置类。
注意依赖版本:确保你使用的SpringBoot版本与其他依赖的版本兼容。不兼容的版本可能导致自动装配失败或出现异常行为。
仔细阅读文档:SpringBoot的官方文档非常详尽,包含了大量关于自动装配的信息和示例。在遇到问题时,首先应该查阅官方文档。
5、小结
配合@EnableAutoConfiguration注解使用时,它主要扮演的是配置查找器的角色。这个注解利用其自身的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为搜索的关键词(Key),来定位并加载一组相关的@Configuration类。
因此,@EnableAutoConfiguration的大致自动配置流程可以描述为以下几个步骤:
首先,它会在classpath中扫描所有的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件。
接着,它会从这些配置文件中提取所有以org.springframework.boot.autoconfigure.EnableAutoConfiguration为key的配置项(注意,这里的key应严格匹配,包括大小写,且不应有笔误,如EnableautoConfiguration应为EnableAutoConfiguration)。
最后,通过Java反射机制,它会实例化那些标注有@Configuration注解的Java配置类,这些类采用JavaConfig的方式定义了IoC容器的配置。完成实例化后,这些配置会被统一注册到Spring的IoC容器中,从而完成了自动配置的过程。