SpringBoot 自动装配原理详解
SpringBoot 自动装配原理详解
SpringBoot的自动装配机制是其核心特性之一,它极大地简化了Spring应用的配置过程。本文将深入探讨自动装配的原理,包括其工作流程、关键注解的作用,以及如何创建自定义的Starter。通过本文的学习,你将能够更好地理解和应用SpringBoot的自动装配功能。
前言
使用过Spring的开发者,一定对XML配置文件印象深刻。即使Spring引入了基于注解的配置方式,但在开启某些Spring特性或引入第三方依赖时,仍然需要进行显式配置。例如,在没有SpringBoot的情况下,创建一个RESTful Web服务需要如下配置:
@Configuration
public class RESTConfiguration {
@Bean
public View jsonTemplate() {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
return view;
}
@Bean
public ViewResolver viewResolver() {
return new BeanNameViewResolver();
}
}
而在Spring Boot项目中,我们只需要添加相关依赖,通过启动下面的main方法即可:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
这种便捷性得益于Spring Boot的自动装配机制。那么,什么是自动装配?它是如何实现的?让我们一探究竟。
什么是SpringBoot自动装配?
自动装配的概念最早出现在Spring Framework中,而Spring Boot在其基础上进行了优化。Spring Boot定义了一套接口规范,规定在启动时扫描外部引用jar包中的META-INF/spring.factories
文件(从Spring Boot 3.0开始,路径改为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
),并将文件中配置的类型信息加载到Spring容器中。
在没有Spring Boot的情况下,引入第三方依赖需要手动配置,非常繁琐。而Spring Boot中,我们只需引入一个Starter即可。例如,要使用Redis,只需添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
引入Starter后,通过少量注解和简单配置就能使用第三方组件的功能。自动装配可以理解为:通过注解或简单配置就能在Spring Boot帮助下实现某项功能。
SpringBoot是如何实现自动装配的?
我们先看Spring Boot的核心注解@SpringBootApplication
:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
public @interface SpringBootApplication {
}
这个注解相当于@Configuration
、@EnableAutoConfiguration
和@ComponentScan
的集合。其中,@EnableAutoConfiguration
是实现自动装配的关键。
@EnableAutoConfiguration:实现自动装配的核心注解
@EnableAutoConfiguration
通过AutoConfigurationImportSelector
类实现自动装配的核心功能:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector:加载自动装配类
AutoConfigurationImportSelector
类实现了ImportSelector
接口,主要通过selectImports
方法获取需要加载到IoC容器中的类:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private static final String[] NO_IMPORTS = new String[0];
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
}
重点关注getAutoConfigurationEntry
方法:
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, 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.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
- 第1步:判断自动装配开关是否打开,默认
spring.boot.enableautoconfiguration=true
。 - 第2步:获取
EnableAutoConfiguration
注解中的exclude
和excludeName
。 - 第3步:读取
META-INF/spring.factories
文件,获取所有需要自动装配的配置类。 - 第4步:通过
@ConditionalOnXXX
注解进行条件筛选,只有满足所有条件的类才会被加载。
如何实现一个Starter
创建一个自定义Starter的步骤如下:
- 创建
threadpool-spring-boot-starter
工程 - 引入Spring Boot相关依赖
- 创建
ThreadPoolAutoConfiguration
- 在
META-INF/spring.factories
文件中配置自动装配类
总结
Spring Boot通过@EnableAutoConfiguration
开启自动装配,通过SpringFactoriesLoader
加载META-INF/spring.factories
中的自动配置类。自动配置类通过@Conditional
注解按需加载,只有满足所有条件的配置才会生效。要使自定义功能生效,需要创建一个Starter并引入相应的依赖。