Spring Boot自动配置源码解析(基于Spring Boot 2.0.2.RELEASE)
在Spring Boot官方介绍中,首一段话是这样的(如下图)。我们可以大概了解到其所表达的含义:我们可以利用Spring Boot写很少的配置来创建一个非常方便的基于Spring整合第三方类库的单体企业级应用。相信使用过Spring Boot的人都知道,她在这方面从前到后的一系列整合。本篇文字将带你进入具体的实现细节。

首先我们写一段Spring Boot应用启动类的代码如下:
package com.springTest; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication //定义Spring Boot应用启动类
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);//启动spring容器等处理
}
}
跟人@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 {
通过名称我们就可以注意到第6行@EnableAutoConfiguration 自动配置,点进去看它的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //自动扫描包路径配置
@Import(AutoConfigurationImportSelector.class) //自动配置导入
public @interface EnableAutoConfiguration {
上面的代码我们可以看到EnableAutoConfiguration利用@Import导入配置组件。 跟踪源码其org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports方法返回的是StringUtils.toStringArray(configurations)。
具体方法代码如下:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
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 StringUtils.toStringArray(configurations);
}
上面代码,我们是通过第8行代码获取所需要的配置类的集合,所以我们继续跟代码,找到如下代码信息:
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
上面的代码通过传入getSpringFactoriesLoaderFactoryClass()和 getBeanClassLoader()的返回值获取配置信息集合。通过跟踪代码,我们可以知道getSpringFactoriesLoaderFactoryClass()方法返回的值为固定的EnableAutoConfiguration.class。 getBeanClassLoader()方法则返回的是this.beanClassLoader对象。深入loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader)方法得知,其返回值的代码为:
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
这段代码明显是将loadSpringFactories(classLoader)返回的集合进行过滤获取key为“EnableAutoConfiguration”的List类型的value值。那么我们继续检查loadSpringFactories的源码:
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 ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); // 找到关于FACTORIES_RESOURCE_LOCATION的定义:public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
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()) {
List<String> factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
上面的代码我们能够很容易的看出它所实现的功能为:加载所有jar包中META-INF/spring.factories文件并解析返回其数据集。到这里,我们不得不对META-INF/spring.factories这个文件产生浓厚的兴趣。通过对Spring Boot所引入的jar包的查找中我们找到了这么一个配置文件如下图(注意箭头指示的内容):
这不正是我们取到多有META-INF/spring.factories文件中定义的数据之后过滤出来所需要的内容吗?忍着激动,我们继续进行分析。
我们应该很容易的猜想到这里面定义的全类名对应的内容应该跟我们所要找的自动配置有关系,所以我们随便先找一个Configuration来验证一下我们的猜想。以org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration为例,我们分析一下它的底层实现:
@Configuration //Spring配置文件注解,表明这是一个配置类
@ConditionalOnClass(CacheManager.class) //底层实现为@Condition 代表CacheManager.class这个类必须存在,否则这个配置文件配置的类将不生效
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class) //对应配置文件的配置
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class) //导入种类的缓存配置
public class CacheAutoConfiguration { @Bean
@ConditionalOnMissingBean
public CacheManagerCustomizers cacheManagerCustomizers(
ObjectProvider<List<CacheManagerCustomizer<?>>> customizers) {
return new CacheManagerCustomizers(customizers.getIfAvailable());
} @Bean
public CacheManagerValidator cacheAutoConfigurationValidator(
CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
return new CacheManagerValidator(cacheProperties, cacheManager);
} @Configuration
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
protected static class CacheManagerJpaDependencyConfiguration
extends EntityManagerFactoryDependsOnPostProcessor { public CacheManagerJpaDependencyConfiguration() {
super("cacheManager");
} } /**
* Bean used to validate that a CacheManager exists and provide a more meaningful
* exception.
*/
static class CacheManagerValidator implements InitializingBean { private final CacheProperties cacheProperties;//自动注入缓存配置 private final ObjectProvider<CacheManager> cacheManager; CacheManagerValidator(CacheProperties cacheProperties,
ObjectProvider<CacheManager> cacheManager) {
this.cacheProperties = cacheProperties;
this.cacheManager = cacheManager;
} @Override
public void afterPropertiesSet() {
Assert.notNull(this.cacheManager.getIfAvailable(),
() -> "No cache manager could "
+ "be auto-configured, check your configuration (caching "
+ "type is '" + this.cacheProperties.getType() + "')");
} } /**
* {@link ImportSelector} to add {@link CacheType} configuration classes.
*/
static class CacheConfigurationImportSelector implements ImportSelector { @Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
} } }
再对应CacheProperties.class的的源码实现:
@ConfigurationProperties(prefix = "spring.cache") //spring中自动导入配置注解
public class CacheProperties { /**
* Cache type. By default, auto-detected according to the environment.
*/
private CacheType type; //spring.cache.type对应
其实分析到这里已经差不多通透了,还有一些实现细节由于篇(wo)幅(hao)原(lan)因(le),不便详叙。如果疑问,欢迎留言,我会认真作答。
Spring Boot自动配置源码解析(基于Spring Boot 2.0.2.RELEASE)的更多相关文章
- Spring Boot 自动配置 源码分析
Spring Boot 最大的特点(亮点)就是自动配置 AutoConfiguration 下面,先说一下 @EnableAutoConfiguration ,然后再看源代码,到底自动配置是怎么配置的 ...
- springboot自动配置源码解析
springboot版本:2.1.6.RELEASE SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfig ...
- SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析
在上一篇博客中分析了springBoot启动流程,大体的轮廓只是冰山一角.今天就来看一下springBoot的亮点功能:自动化装配功能. 先从@SpringBootApplication开始.在启动流 ...
- SpringBoot Profile使用详解及配置源码解析
在实践的过程中我们经常会遇到不同的环境需要不同配置文件的情况,如果每换一个环境重新修改配置文件或重新打包一次会比较麻烦,Spring Boot为此提供了Profile配置来解决此问题. Profile ...
- SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的
系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...
- SpringBoot自动配置源码调试
之前对SpringBoot的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下来就对自动配置进行源码调试,探 ...
- Spring5源码解析-论Spring DispatcherServlet的生命周期
Spring Web框架架构的主要部分是DispatcherServlet.也就是本文中重点介绍的对象. 在本文的第一部分中,我们将看到基于Spring的DispatcherServlet的主要概念: ...
- String,StringBuffer和StringBuilder源码解析[基于JDK6]
最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西.其实,JDK的源码是越读越有味的.下面总结一下 ...
- Spring Boot系列(三):Spring Boot整合Mybatis源码解析
一.Mybatis回顾 1.MyBatis介绍 Mybatis是一个半ORM框架,它使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJOs(普通的Java 对象)映射成数据库中的记 ...
随机推荐
- apt-get Ubuntu本地ISO镜像入源
转自http://blog.csdn.net/binchel/article/details/21486999 在没有网络的情况下,本地镜像源不实为一个上等的权宜之计! 目前linux的两大主流包管理 ...
- 多线程编程 NSOperation
前言 1.NSThread的使用,虽然也可以实现多线程编程,但是需要我们去管理线程的生命周期,还要考虑线程同步.加锁问题,造成一些性能上的开销.我们也可以配合使用NSOperation和NSOper ...
- 读JVM相关的一些笔记
1.JVM的运行模式 vm一般有两种运行模式,client和server(JDK 7 后有第三种 Tiered server,后续会涉及到). client : 启动快,内存占用少,JIT编译器生成代 ...
- VS 和 VAssistX 常用快捷键
----------------------------------------------------------------函数跳转-------------------------------- ...
- Drupal7.8的安装注意的问题
首先推荐在安装之前,首先阅读一下官方的Installation guide ,说实话话,这玩意安装没有Joomla安装那么平滑,大多数问题,guide都会提到.我是先安装后看的这个guide,比较折腾 ...
- Download and Install Apache Zookeeper on Ubuntu
http://www.techburps.com/misc/download-and-install-apache-zookeepr/36 In previous article of this Bi ...
- Sass快速入门学习笔记
1. 使用变量; sass让人们受益的一个重要特性就是它为css引入了变量.你可以把反复使用的css属性值 定义成变量,然后通过变量名来引用它们,而无需重复书写这一属性值.或者,对于仅使用过一 次的属 ...
- ArcCore重构-目标文件结构化
基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5 基本问题 3. 编译系统中所有代码文件通过搜索路径(VPATH)中搜索,存在名称污染问题,需加入路径信息: ...
- linux基础-系统安装教程篇(centos6.5)
一.linux系统简介: Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程 ...
- 第二次作业 单例模式的SessionFactory
一.基础Hibernate环境搭建(参见http://www.cnblogs.com/sangewuxie/p/9004968.html) 二.实体类User及User.hbm.xml配置 1.Use ...