Springboot之自动装配原理
一、@SpringBootApplication
SpringBoot 的核心注解@SpringBootApplication
可以看作是 @SpringBootConfiguration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//启用 SpringBoot 的自动配置机制
@SpringBootConfiguration
//允许在上下文中注册额外的 bean 或导入其他配置类
@EnableAutoConfiguration
//扫描被@Component (@Service,@Controller)注解的 bean
//注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
二、@EnableAutoConfiguration
@EnableAutoConfiguration
主要作用就是启用 SpringBoot 的自动配置机制,主要关注@Import({AutoConfigurationPackages.Registrar.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//利用@Import(AutoConfigurationPackages.Registrar.class)来进行默认扫包行为(主程序所在包及其子包)
@AutoConfigurationPackage
//自动配置是否导入的选择器
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
三、AutoConfigurationImportSelector
AutoConfigurationImportSelector
类的ImportSelector
选择器定义如下
//定义了一个selectImports方法用来选择哪些配置类可以加载
public interface ImportSelector {
...
String[] selectImports(AnnotationMetadata importingClassMetadata);
...
}
//DeferredImportSelector是ImportSelector中的子接口
public interface DeferredImportSelector extends ImportSelector {
...
}
AutoConfigurationImportSelector
实现了DeferredImportSelecto
r接口
//AutoConfigurationImportSelector实现了DeferredImportSelector接口
public class AutoConfigurationImportSelector implements DeferredImportSelector, xxxx,xxxx {
//实现了ImportSelector方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//判断自动装配开关是否打开
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//通过getAutoConfigurationEntry()方法,获取所有需要装配的bean
AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
//判断自动装配开关是否打开,默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//用于获取EnableAutoConfiguration注解中的exclude和excludeName。
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//找出配置中的xxxAutoConfiguration,具体见下方
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = this.removeDuplicates(configurations);
//过滤exclude和excludeName的
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);
}
}
经过上述方法就将需要加载的配置类,自动装配了!
备注:
从配置中获取自动配置类的方式
springboot2.7.0
目前会向后兼容老版本配置模式spring.factories。
原配置方式 | 当前配置方式 |
---|---|
META-INF/spring.factories | META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |
@Configuration | @AutoConfiguration |
新注解@AutoConfiguration
是被用在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
中的自动化配置类上用来替换@Configuration
、@AutoConfigurationAfter
、@AutoConfigurationBefore
注解,其中@Configuration
对应的proxyBeanMethods
属性值一直为false。
条件配置
@ConditionalOnBean
:当容器里有指定 Bean 的条件下@ConditionalOnMissingBean
:当容器里没有指定 Bean 的情况下@ConditionalOnSingleCandidate
:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean@ConditionalOnClass
:当类路径下有指定类的条件下@ConditionalOnMissingClass
:当类路径下没有指定类的条件下@ConditionalOnProperty
:指定的属性是否有指定的值@ConditionalOnResource
:类路径是否有指定的值@ConditionalOnExpression
:基于 SpEL 表达式作为判断条件@ConditionalOnJava
:基于 Java 版本作为判断条件@ConditionalOnJndi
:在 JNDI 存在的条件下差在指定的位置@ConditionalOnNotWebApplication
:当前项目不是 Web 项目的条件下@ConditionalOnWebApplication
:当前项目是 Web 项 目的条件下