自动装配原理
springboot 版本:2.4.3

SpringBootApplication
springboot启动类必须要加@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 {
1
2
3
4
5
6
7
8
9
10
抛开元数据注解来说,SpringBootApplication注解主要由@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan组成。这三个又有不同的作用如下:

@SpringBootConfiguration:被@Configuration标记,表示这是个springboot配置,支持JavaConfig的方式来进行配置。
@EnableAutoConfiguration:表示开启自动装配(重点介绍)
@ComponentScan:扫描注解,扫描basePackages包下的bean并将他们注入到IOC容器中,比如:@Service@Controller@Component等注解。
EnableAutoConfiguration
真正开启自动配置的还是@EnableAutoConfiguration注解,来看下EnableAutoConfiguration注解源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
1
2
3
4
5
6
7
@EnableAutoConfiguration 又是由@AutoConfigurationPackage@Import注解组成。

@AutoConfigurationPackage是一个复合注解的,它在内部使用@Import(AutoConfigurationPackages.Registrar.class)注解,Registrar是AutoConfigurationPackages的一个内部类,它的作用就是注册一个springboot启动类所在的包名,这个包名可以供列如JPA的使用。

AutoConfigurationImportSelector通过selectImports方法将配置类导入,从而完成bean的装配

AutoConfigurationImportSelector
AutoConfigurationImportSelector实现了DeferredImportSelector接口,DeferredImportSelector是ImportSelector的变种,它是一个延迟选择器。实现了DeferredImportSelector接口的子类如果重新了getImportGroup方法并返回DeferredImportSelector内部接口Group的子类,DeferredImportSelector接口的子类的子类将不会调用selectImports而是调用Group的selectImports方法。

接下来看看AutoConfigurationImportSelector重写了getImportGroup方法并返回一个内部类AutoConfigurationGroup,AutoConfigurationGroup#selectImports方法只是对配置数组进行排序筛选,真正处理自动配置的流程的是process方法。
process方法源码如下:

@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format(“Only %s implementations are supported, got %s”,
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
process方法就是对AutoConfigurationGroup一些属性的填充,起作用的还是AutoConfigurationImportSelector.getAutoConfigurationEntry方法。
getAutoConfigurationEntry方法中经过各种判断过滤、去重等操作,最后返回AutoConfigurationEntry对象。源码如下

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获取EnableAutoConfiguration注解的exclude和excludeName属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取所有配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//去除重复配置类
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
//移除 exclude的配置类
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
getAutoConfigurationEntry 筛选的自动配置类:

getAutoConfigurationEntry方法中要重点分析的是getCandidateConfigurations方法。getCandidateConfigurations的作用是获取所有自动装配的配置类的全限定名。

来看下getCandidateConfigurations方法源码:

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 “

  1. + "are using a custom packaging, make sure that file is correct.");
  2. return configurations;
  3. }

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
1
2
3
4
5
6
7
8
9
10
11
这里面用到了SpringFactoriesLoader是spring提供的一种加载配置的方式,它会将类从配置文件中读取到,然后利用反射将bean加载到IOC容器中。

SpringFactoriesLoader.loadFactoryNames中会加载META-INF/spring.factories自动配置类。这些配置类在spring.factories文件中是以key=value的形式存储的,来看下部分自动配置类:

Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
来看下SpringFactoriesLoader.loadFactoryNames源码:

public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

  1. private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
  2. Map<String, List<String>> result = cache.get(classLoader);
  3. if (result != null) {
  4. return result;
  5. }
  6. result = new HashMap<>();
  7. try {
  8. Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
  9. while (urls.hasMoreElements()) {
  10. URL url = urls.nextElement();
  11. UrlResource resource = new UrlResource(url);
  12. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  13. for (Map.Entry<?, ?> entry : properties.entrySet()) {
  14. String factoryTypeName = ((String) entry.getKey()).trim();
  15. String[] factoryImplementationNames =
  16. StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
  17. for (String factoryImplementationName : factoryImplementationNames) {
  18. result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
  19. .add(factoryImplementationName.trim());
  20. }
  21. }
  22. }
  23. // Replace all lists with unmodifiable lists containing unique elements
  24. result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
  25. .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
  26. cache.put(classLoader, result);
  27. }
  28. catch (IOException ex) {
  29. throw new IllegalArgumentException("Unable to load factories from location [" +
  30. FACTORIES_RESOURCE_LOCATION + "]", ex);
  31. }
  32. return result;
  33. }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
loadFactoryNames方法只是传递一个org.springframework.boot.autoconfigure.EnableAutoConfiguration作为key,然后取到对应的自动配置类列表。
最终调用的是loadSpringFactories方法,loadSpringFactories会从jar包中找到spring.factories文件然后将其中的自动配置类存到一个map中,从下图可以看到map中存在很多bean,loadFactoryNames方法在加载自动配置类时只取了一个key。弱水三千,只取一瓢。

loadSpringFactories返回结果:

自动装配流程图大致如下:

总结
EnableAutoConfiguration注解开启自动装配,其上的标记的@Import(AutoConfigurationImportSelector.class)注解中导入配置类
AutoConfigurationImportSelector实现DeferredImportSelector接口,并重写了getImportGroup方法并返回AutoConfigurationImportSelector.AutoConfigurationGroup,AutoConfigurationImportSelector.AutoConfigurationGroup.process开始处理自动配置流程。
AutoConfigurationImportSelector.getCandidateConfigurations获取所有配置类getAutoConfigurationEntry方法筛选,去重、移除不符合条件的自动配置类。
SpringFactoriesLoader.loadSpringFactories从jar包中找到所有META-INF/spring.factories文件并读取自动配置类,存放到map中, loadFactoryNames方法通过全限定名org.springframework.boot.autoconfigure.EnableAutoConfiguration找到自动配置类。
最后经过层层筛选,去重、移除不符合条件的bean,由ConfigurationClassPostProcessor#processConfigBeanDefinitions注册所有的自动配置类。
能力一般,水平有限,如有错误,请多指出。
如果对你有用点个关注给个赞呗
————————————————
版权声明:本文为CSDN博主「码猿笔记」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39654841/article/details/123352176

更多相关文章

  1. Android第九讲——网络(六)xUtils
  2. Android(安卓)的AsyncTask使用
  3. Android(安卓)jetpack Room数据库(一)基本使用
  4. 升级android studio3.0遇到的问题
  5. Android标题栏(titlebar)显示进度条
  6. android proguard 错误处理
  7. API 23及之后版本关于用android studio 中LocationManager的方法
  8. Android下按扭的使用方法
  9. android登录简单窗口

随机推荐

  1. Android 让你的 EditText 只接受指定字符
  2. Android 呼吸灯流程分析(二)
  3. android书籍
  4. android:向手机卡上写入文件时总是不成功,
  5. Android -- Dialog(AlertDialog)
  6. android的ITC
  7. 2011.09.23(2)——— android sample之Note
  8. Ubuntu 18.04 配置android 源码开发/编译
  9. android 按钮按下效果(文字颜色和按钮同时
  10. Android的View抗锯齿