一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
什么是自动装配
在使用SpringBoot的时候,会自动将Bean装配到IoC容器中,自动装配大致过程如下:
- 获取到组件META-INF文件夹下的spring.factories文件
- spring.factories文件中列出需要注入IoC容器的类
- 将实体类注入到IoC容器中进行使用
自动装配原理
通过SpringBoot启动类 来分析整个过程,首先看下启动类的代码:
@SpringBootApplication
public class CompanyProjectApplication {
public static void main(String[] args) {
SpringApplication.run(RuoYiApplication.class, args);
}
@SpringBootApplication
可以看到最主要部分就是@SpringBootApplication注解,进入注解类,我们能够发现@SpringBootApplication这个注解其实是一个组合注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
@Target({ElementType.TYPE}) // 表明 修饰的注解的位置 TYPE 表示只能修饰类
@Retention(RetentionPolicy.RUNTIME) // 表明注解的作用域
@Documented // API 文档抽取的时候会将该注解 抽取到API文档中
@Inherited // 表示注解的继承
@SpringBootConfiguration这个注解的本质其实是@Configuration注解。
@ComponentScan注解,该注解的作用是用来指定扫描路径的,如果不指定特定的扫描路径的话,扫描的路径是当前修饰的类所在的包及其子包。
那么就剩@EnableAutoConfiguration,这个注解就是SpringBoot自动装配的关键。
@EnableAutoConfiguration
进入@EnableAutoConfiguration注解,可以看到@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})
@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 {};
}
通过@AutoConfigurationPackage注解将添加该注解的类所在的package作为自动配置package进行管理。
而@EnableAutoConfiguration注解最重要的是AutoConfigurationImportSelector.class,将需要装配的类装配到IoC容器中,下面重点分析一下这个类的实现
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
进入到AutoConfigurationImportSelector 类,根据断点debug,进入getAutoConfigurationEntry方法,调用到了方法getCandidateConfigurations,调用到了 SpringFactoriesLoader的loadFactoryNames,通过debug可以看到加载到了META-INF/spring.factories文件
configurations = this.filter(configurations, autoConfigurationMetadata);调用下面方法
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
Iterator var8 = this.getAutoConfigurationImportFilters().iterator();
while(var8.hasNext()) {
AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var8.next();
this.invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for(int i = 0; i < match.length; ++i) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
} else {
List<String> result = new ArrayList(candidates.length);
int numberFiltered;
for(numberFiltered = 0; numberFiltered < candidates.length; ++numberFiltered) {
if (!skip[numberFiltered]) {
result.add(candidates[numberFiltered]);
}
}
if (logger.isTraceEnabled()) {
numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList(result);
}
}
可以看到匹配方法 match。 autoConfigurationMetadata
,的本质是 加载的 META-INF/spring-autoconfigure-metadata.properties
的文件中的内容。过滤之后仅剩46个文件
到这其实我们就已经给大家介绍完了SpringBoot的自动装配原理。在网上找到了一张总结好的流程图如下:
~好了,本文就给大家介绍到这里,感觉有帮助的,留下个赞或评论再走吧!谢啦~ 💐