简述Spring Boot的自动装配

从配置文件说起

使用Spring Boot时我们就知道,Spring Boot有一个全局配置文件:application.properties或application.yml。

我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等,然而我们实际用到的往往只是很少的一部分,那么这些属性是否有据可依呢?答案当然是肯定的,这些属性都可以在官方文档中查找到:

https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#common-application-properties

那么问题也接踵而来,Spring Boot如何使这些配置在项目中生效的尼?

从启动类的注解开始

首先让我们将目光聚集到启动类上,是不是每个启动类都有这个注解–@SpringBootApplication 这个注解是Spring Boot项目必不可少的注解。那么自动配置原理一定和这个注解有着千丝万缕的联系!
@SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,翻译成人话就是开启自动配置,其定义如下:
在这里插入图片描述
在EnableAutoConfiguration中通过Import引入了SpringBoot定义的AutoConfigurationImportSelector
这个类内容比较多,我们只需看下最主要的逻辑代码即可


```java
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
    
    
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    
    
if (!isEnabled(annotationMetadata)) {
    
    
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata =
AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//主要逻辑在getAutoConfigurationEntry这个方法
AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(
autoConfigurationMetadata, annotationMetadata);
return
StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
    
    
if (!isEnabled(annotationMetadata)) {
    
    
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//通过getCandidateConfigurations方法获取所有需要加载的bean
List<String> configurations =
getCandidateConfigurations(annotationMetadata,
attributes);
//去重处理
configurations = removeDuplicates(configurations);
//获取不需要加载的bean,这里我们可以通过spring.autoconfigure.exclude人为配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
//发送事件,通知所有的AutoConfigurationImportListener进行监听
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
//这里是获取bean渠道的地方,重点看SpringFactoriesLoader#loadFactoryNames
protected List<String> getCandidateConfigurations(AnnotationMetadata
metadata,
AnnotationAttributes attributes) {
    
    
//这里的getSpringFactoriesLoaderFactoryClass()最终返回
EnableAutoConfiguration.class
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in METAINF/
spring.factories. If you "
+ "are using a custom packaging, make sure that file is
correct.");
return configurations;
}
}

从上面的逻辑可以看出,最终获取bean的渠道在SpringFactoriesLoader.loadFactoryNames

public final class SpringFactoriesLoader {
    
    
public static final String FACTORIES_RESOURCE_LOCATION = "METAINF/
spring.factories";
private static final Log logger =
LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache =
new ConcurrentReferenceHashMap();
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable
ClassLoader classLoader) {
    
    
String factoryClassName = factoryClass.getName();
//通过factoryClassName获取相应的bean全称
//上面传入的factoryClass是EnableAutoConfiguration.class
return
(List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,
Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable
ClassLoader classLoader) {
    
    
MultiValueMap<String, String> result =
(MultiValueMap)cache.get(classLoader);
if (result != null) {
    
    
return result;
} else {
    
    
try {
    
    
//获取工程中所有META-INF/spring.factories文件,将其中的键值组合成Map
Enumeration<URL> urls = classLoader != null ?
classLoader.getResources("META-INF/spring.factories") :
ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
    
    
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties =
PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
    
    
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName =
((String)entry.getKey()).trim();
String[] var9 =
StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
    
    
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
    
    
throw new IllegalArgumentException("Unable to load factories
from location [META-INF/spring.factories]", var13);
}
}
}
private static <T> T instantiateFactory(String instanceClassName, Class<T>
factoryClass, ClassLoader classLoader) {
    
    
try {
    
    
Class<?> instanceClass = ClassUtils.forName(instanceClassName,
classLoader);
if (!factoryClass.isAssignableFrom(instanceClass)) {
    
    
throw new IllegalArgumentException("Class [" + instanceClassName
+ "] is not assignable to [" + factoryClass.getName() + "]");
} else {
    
    
return ReflectionUtils.accessibleConstructor(instanceClass, new
Class[0]).newInstance();
}
} catch (Throwable var4) {
    
    
throw new IllegalArgumentException("Unable to instantiate factory
class: " + factoryClass.getName(), var4);
}
}
}

每个jar都可以定义自己的META-INF/spring.factories ,jar被加载的同时 spring.factories里面定义的
bean就可以自动被加载
在这里插入图片描述这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_37669050/article/details/103404206