一、SpringBoot自动装配的原理
前言:
SpringBoot自动装配是一种思想,它将约定大于配置的思想实现的淋漓尽致,SpringBoot通过@Configuration,@Import注解实现配置文件的编写和导入
在利用spring.factores规定将每个集成进SpringBoot的内的组件都将自己的配置类的全路径写在此文件中,再由SpringBoot程序去读取并将其加入到SpringBoot的IOC容器内。
一、SpringBoot自动装配源码解析
1、Spring应用自动装配从@SpringBootApplication注解开始,在此注解内@EableAutoCOnfoguration注解
@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 {
2、进入EableAutoConfiguration注解
有两个关键注解:
1、@AutoConfigurationPackage:配置文件包注册
2、@Import 导入了AutoConfigurationImportSelector这个类,这个类的作用是自动配置的文件选择器
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
首先看@AutoConfigurationPackage:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
# 下面这句代码是运行了自动运行的包选择器在此方法是将所有组件的配置类
# 加载到Spring中完成Bean的注册
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
再看@Import()注解导入的AutoConfigurationImportSelector.class这个类在这个类中关键代码在getCandidateConfigurations这行代码就是用于加载SpringBootStarter中配置的Spring.factores文件内的配置类的全路径将starter组件的配置类加载到Spring-boot程序中
SpringFactoriesLoader是Spring-boot内置的一个文件加载器,主要加载的就是starter下MINT-INF/spring.factores文件内的配置类SpringFactoriesLoader下的方法很多列举几个核心的方法
// 获取自动配置的类名称
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//SpringFactoriesLoader是Spring-boot内置的一个文件加载器,主要加载的就是starter下MATE-INF/spring.factores文件内的配置类
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;
}
// 获取自动配置类的实体
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
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 = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
// 核心方法用于查到需要加载的自动配置
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 调用获取实体方法
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
再看SpringFactoriesLoader类的源码
public final class SpringFactoriesLoader {
/**
这下就说的通了META-INF/spring.factories的作用就是约定每个集成到SpringBoot内的应用在MATE-INF下创建一个的spring.factories文件,并将需要被Spring
boot管理的bean加载到Spring-boot中
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
private SpringFactoriesLoader() {
}
/**
此方法是用于加载spring.factories内的key的
* Load and instantiate the factory implementations of the given type from
* {@value #FACTORIES_RESOURCE_LOCATION}, using the given class loader.
* <p>The returned factories are sorted through {@link AnnotationAwareOrderComparator}.
* <p>If a custom instantiation strategy is required, use {@link #loadFactoryNames}
* to obtain all registered factory names.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading (can be {@code null} to use the default)
* @throws IllegalArgumentException if any factory implementation class cannot
* be loaded or if an error occurs while instantiating any factory
* @see #loadFactoryNames
*/
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
// 根据指定的key获取key的值
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
List<T> result = new ArrayList<>(factoryImplementationNames.size());
// 调用instantiateFactory方法创建对应的实例
for (String factoryImplementationName : factoryImplementationNames) {
// 循环创建加载器实例将实例加入到结果集中进行返回
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
/**
获取值也就是自动配置文件的全路径
* Load the fully qualified class names of factory implementations of the
* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
* class loader.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @throws IllegalArgumentException if an error occurs while loading factory names
* @see #loadFactories
*/
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 获取加载路径的地址
Enumeration<URL> urls = (classLoader != null ?
//从classpath:MATE-INF/spring.factores 下获取的加载的地址
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 下面为加载信息
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
// 实例创建
@SuppressWarnings("unchecked")
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
try {
Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
throw new IllegalArgumentException(
"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
}
// 通过反射串联
return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
ex);
}
}
}
以上就是自动配置的一些关键类那么下面从run方法开始走一遍加载的流程
1、主启动函数
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2、进入到@SpringBootApplication注解内的@EnableAutoConfiguration 注解,此注解导入了一个AutoConfigurationImportSelector类此类会被加载到SpringIOC容器内
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
3、进入AutoConfigurationImportSelector类,此类有个核心的方法getAutoConfigurationEntry(旧版本调用的是selectImport()方法),此方法的核心作用就是为了加载配置获取MATE-INF下的spring.factores内的配置信息
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取需要被的加载的到IOC的配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 对获取的配置类进行过滤的去重
configurations = removeDuplicates(configurations);
// 返回被全部被候选排除的排除项
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查确认将exclusions内的排除项在configurations内删除
checkExcludedClasses(configurations, exclusions);
// 删除排除项
configurations.removeAll(exclusions);
// 对配置类进行过滤
configurations = filter(configurations, autoConfigurationMetadata);
//
fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回通过筛选等没有被筛选掉的配置类
return new AutoConfigurationEntry(configurations, exclusions);
}
4、看下getCandidateConfigurations是怎么获取到配置类的
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 调用了SpringFactoriesLoader.loadFactoryNames()方法,上面介绍到了这个方法就是加载组件MATE-INF下的Spring.factores内的配置类信息
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;
}
loadFactoryNames()方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
核心加载方法loadSpringFactories
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 获取的ULR枚举类
Enumeration<URL> urls = (classLoader != null ?
//public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 获取classpath下META-INF/spring.factories 文件内的数据
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
// 创建返回结果的数据集对象
result = new LinkedMultiValueMap<>();
// 开始对枚举类Enumeration 进行解析
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
// 将其放入缓存
cache.put(classLoader, result);
// 返回结果
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
到此其实Spring-boot的自动装配就已经很清晰了,主要的核心代码也完成了。