目录
一、介绍
二、Spring Boot实现自动装配的简单流程(基于2.3.5.RELEASE版本)
三、总结
一、介绍
什么是Spring Boot的自动装配?
以下描述部分来自Spring Boot官网:
- Spring Boot自动配置尝试根据您添加的jar依赖项自动配置您的Spring应用程序。
- 您需要通过将@EnableAutoConfiguration或@SpringBootApplication注释添加到您的一个@Configuration类中来选择自动配置。您应该只添加一个@SpringBootApplication或@EnableAutoConfiguration注释。
补充:
- 上诉说到Spring Boot会根据添加的jar依赖项自动配置您的Spring应用程序,具体的实现是通过扫描到引用的jar包中的META-INF/spring.factories文件,获取到你的配置类,文件内容大致如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ricardo.cn.config.MyAutoConfigure
通过以上描述,个人理解为,自动装配就是能够为你创建你在jar包中定义的Bean,将其装配到容器中,供你使用你在jar包中实现的功能。
如果你想开发一个能够被Spring Boot自动装配所识别的Spring Boot Starter组件,那么请参考以下我的另外一篇博客,包含了开发的具体流程:
[自动装配系列]spring-boot-starter组件自定义开发及应用_明天再去学习的博客-CSDN博客
二、Spring Boot实现自动装配的简单流程(基于2.3.5.RELEASE版本)
1、通过上诉描述,Spring Boot想要实现自动装配,首先,你得需要在你的配置类中使用@SpringBootApplication或@EnableAutoConfiguration注解,毫无疑问,我们需要关注的只是@EnableAutoConfiguration注解,为什么这么说呢,请看@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 {}
可以看到,即使是@SpringBootApplication注解,其中也包含@EnableAutoConfiguration注解,所以@EnableAutoConfiguration注解是自动装配功能主入口。
2、@EnableAutoConfiguration注解内容如下:
@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 {};
}
官网中有这么一句话:
The
@Import
annotation can be used to import additional configuration classes
大致意思是说,@Import注解可以用于 导入其他配置类,所以,我们将关注点放在AutoConfigurationImportSelector.class上。
3、AutoConfigurationImportSelector.class的基础信息如下:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
public interface DeferredImportSelector extends ImportSelector {}
public interface ImportSelector {
}
当我定位到这个类之后,很疑惑,该把断点定位在何处,百度之后,有说是selectImport方法,有说是process方法,那到底是哪一个呢?很简单,两个方法都打一下断点。
3、将断点打在AutoConfigurationImportSelector.class的selectImport方法上。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
将断点打到此处后,启动debug模式,发现进不来,说明我这个版本的Spring Boot,selectImport方法不是主入口。
4、将断点打在AutoConfigurationImportSelector.class的process方法上。
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
});
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();
while(var4.hasNext()) {
String importClassName = (String)var4.next();
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
将断点打到此处后,启动debug模式,发现进来了,说明我这个版本的Spring Boot,process方法是主入口。
在该方法中一步步debug走下去,查看参数内容:
当执行完getAutoConfigurationEntry方法时,可以看到返回结果如上图所示,都是AutoConfiguration结尾的配置(WhiteListAutoConfiguratio是我自定义的Spring Boot Starter组件,看到他之后,更加确定是getAutoConfigurationEntry方法了)。
5、给getAutoConfigurationEntry方法打断点。
protected AutoConfigurationImportSelector.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 AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
在该方法中一步步debug走下去,查看参数内容:
当执行完getCondidateConfigurations方法时,可以看到返回结果如上图所示,都是AutoConfiguration结尾的配置,可以确定自动装配与该方法有关。
6、查看getCondidateConfigurations方法。
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;
}
通过该方法中英文描述可以看出,自动装配扫描的是META-INF/spring.factories文件。
7、通过上诉流程,进入到SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
进入到关键方法loadSpringFactories,一步步断点走下去,urls中包含了我们的所有外部jar包(通过debug查看到了urls内容),然后遍历每个jar包,扫描到我们jar包下的META-INF/spring.factories,获取到我们的配置类。
当调用完上诉步骤后,返回结果如下:
在步骤6中,又通过EnableAutoConfiguration.class从上诉集合中取到相关的value值列表。
8、至此,我们便拿到了需要自动装配的配置类,进行初始化。
三、总结
该文章主要是作为我以下的文章的支撑,只是作为学习参考,如果内容有错误的地方,可以进行留言提示,我看到的话会进行更正,谢谢:
[自动装配系列]spring-boot-starter组件自定义开发及应用_明天再去学习的博客-CSDN博客