概述
在学习Spring Boot中,最核心的两个原理就是 约定优于配置,自动装配,其实约定也是用于自动装配的,今天我们来分析一下,Spring Boot的自动装配是这么个过程。
Spring Boot 是这么开启自动装配?
@EnableAutoConfiguration 注解开启自动装配功能,这个注解是在启动类@SpringBootApplication 注解里面,所以当run 启动项目时就自动开启了spring boot 的自动装配功能
@EnableAutoConfiguration 是这么做到自动装配的呢
@Enable注解在spring 的作用就是把相关组件的Bean 装配到 Ioc 容器中。如果基于JavaConfig 的形式来完成Bean的装配的话就必须要使用 @Configuration 和@Bean注解,而@Enable 本质上就是针对这两个注解的封装,并且这些注解里面还携带了一个 @Import注解,答案就在@Import注解的配置类,用来描述自动装配的实现类
@Import 注解的作用?
@Import注解的作用就是 Spring 会解析到 @Import导入到配置类,从而通过这个配置类的描述来完成Bean的装配
@AutoConfigurationPackage
在进入@EnableAutoConfiguration 注解中,我们可以看到 不仅有 @Import 还有 @AutoConfigurationPackage 这个注解的作用就是:把使用了该注解的类的所在的包及子包下所有的组件扫描到Spring Ioc容器中。
AutoConfigurationImportSelector 实现,这么去做到自动装配?
AutoConfigurationImportSelector 类实现了 ImportSelector,中的selectImports 抽象方法,并且返回一个数组,这个方法的实现就是Spring Boot自动装配的实现,这里会把需要自动装配的类配置好,放到到这个数组,然后进行批量装配。
分析 selectImports 中的实现?
当前Spring Boot 版本为2.3.10.BUILD-SNAPSHOT 在低版本中,这里面应该还有一段代码是用处理:
1.META-INF/spring-autocomfigure-metadataproperties中加载自动装配的条件元数据,只有满足条件的Bean才能进行自动装配,在当前版本中,我们并没有看到这段处理代码,
2.收集所有符合条件的配置类,完成自动装配
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
这段代码中重点就在于getAutoConfigurationEntry方法中,这里是收集自动装配到配置类。
getAutoConfigurationEntry 实现,这么去收集符合条件的配置类?
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
分析一下代码:
AnnotationAttributes attributes = getAttributes(annotationMetadata);
读取 EnableAutoConfiguration 注解中的属性信息等 (需要排除的配置类)
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
也就是定义的属性字段,这里主要就是为了做排除自动配置所做的
List configurations = getCandidateConfigurations(annotationMetadata, attributes);
这里是最重要的点,获取所有自动装配的配置类。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
这里使用了 SpringFactoriesLoader 约定俗成的加载方式,也点类似java中的SPI,简单来说就是通过 classpath 读取 META-INF/spring.factories,这个文件就存储了我们需要自动装配的配置类,文件以key-value方法存储
文件中就以这种形式存在:
里面的格式就这样,条件装配,这样子我们就可以把他自动装配进去。其实这里我理解就是 Spring boot Starter 约定的一些文件,然后读取出来进行装配。
configurations = removeDuplicates(configurations);
去掉重复的配置类,里面的实现很简单,转换成 LinkedHashSet
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
Set exclusions = getExclusions(annotationMetadata, attributes);
根据EnableAutoConfiguration注解中属性,获取不需要自动装配的类名单
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
exclude 不需要自动装配的类
excludeName 不需要自动装配类的名称
getExcludeAutoConfigurationsProperty 获取配置文件中不需要自动装配的类:
String ENABLED_OVERRIDE_PROPERTY = “spring.boot.enableautoconfiguration”;
configurations.removeAll(exclusions);
取代不需要装配的配置类
configurations = getConfigurationClassFilter().filter(configurations);
进行过滤操作,不需要装配的类
fireAutoConfigurationImportEvents(configurations, exclusions);
自动装配的导入事件,事件可能包括候选的配置名单,和排除的配置名单
return new AutoConfigurationEntry(configurations, exclusions);
返回需要自动装配的类。
至此Spring Boot 自动装配原理分析完毕。
Spring Boot 自动装配核心过程
- 通过@Import(AutoConfigurationImportSelector.class) 实现配置类的导入,可以多个类装配注入
- AutoConfigurationImportSelector 实现了 ImportSelector 接口中的selectImports 方法用于实现选择性批量配置类的装配
- 通过 SpringFactoriesLoader 约定俗成的加载方式,读取classpath 下的META-INF/spring.factories ,实现自动装配的配置类
- 通过条件筛选,把不符合条件的配置类移除,最终完成自动装配。
最后
以上就是曾经心情为你收集整理的深入理解Spring Boot 自动装配原理的全部内容,希望文章能够帮你解决深入理解Spring Boot 自动装配原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复