在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)的更多相关文章

  1. Spring Boot 自动配置 源码分析

    Spring Boot 最大的特点(亮点)就是自动配置 AutoConfiguration 下面,先说一下 @EnableAutoConfiguration ,然后再看源代码,到底自动配置是怎么配置的 ...

  2. springboot自动配置源码解析

    springboot版本:2.1.6.RELEASE SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfig ...

  3. SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析

    在上一篇博客中分析了springBoot启动流程,大体的轮廓只是冰山一角.今天就来看一下springBoot的亮点功能:自动化装配功能. 先从@SpringBootApplication开始.在启动流 ...

  4. SpringBoot Profile使用详解及配置源码解析

    在实践的过程中我们经常会遇到不同的环境需要不同配置文件的情况,如果每换一个环境重新修改配置文件或重新打包一次会比较麻烦,Spring Boot为此提供了Profile配置来解决此问题. Profile ...

  5. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  6. SpringBoot自动配置源码调试

    之前对SpringBoot的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下来就对自动配置进行源码调试,探 ...

  7. Spring5源码解析-论Spring DispatcherServlet的生命周期

    Spring Web框架架构的主要部分是DispatcherServlet.也就是本文中重点介绍的对象. 在本文的第一部分中,我们将看到基于Spring的DispatcherServlet的主要概念: ...

  8. String,StringBuffer和StringBuilder源码解析[基于JDK6]

    最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西.其实,JDK的源码是越读越有味的.下面总结一下 ...

  9. Spring Boot系列(三):Spring Boot整合Mybatis源码解析

    一.Mybatis回顾 1.MyBatis介绍 Mybatis是一个半ORM框架,它使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJOs(普通的Java 对象)映射成数据库中的记 ...

随机推荐

  1. C# PDF Page操作——设置页面切换按钮

    概述 在以下示例中,将介绍在PDF文档页面设置页面切换按钮的方法.示例中将页面切换按钮的添加分为了两种情况,一种是设置按钮跳转到首页.下页.上页或者最后一页,另一种是设置按钮跳转到指定页面.两种方法适 ...

  2. 八、Join 连接查询

    文档目录 开发中...

  3. eclipse调试的方法和技巧

    eclipse调试图标所代表的含义: Step into 单步进入-将进入执行的方法内部继续执行. Step over  单步前进-执行下一步. Step return – 单步退出-跳出正在执行的方 ...

  4. 阿里云服务器连接邮箱SMTP服务器time out的解决

    给官方提了个工单,回复如下: 去年9月底开始,出于上级对垃圾邮件管控的要求,新购VPC服务器限制了25端口,我们建议您使用邮件服务商的加密465端口. 或者您查询下所希望访问的发信服务是否提供了像阿里 ...

  5. how to select checkbox on cli environment?

    generally , u can focus on this checkbox and press blank key Ok,that's shit.    

  6. zinnia项目功能分析

    Zinnia是基于Django开发的一个开源博客系统,近期为了写一个类博客系统特对它做功能分析,+号的多少表明这个功能对于博客的重要性: ++评论:Comments 站点图:Sitemaps ]压缩视 ...

  7. C#避免踩坑之如何添加paint事件

    看截图: 首先,右击->属性 然后出来这个界面. 接下来,注意看这个界面的上面:鼠标悬停这个闪电符号,看到没,事件!! 那个闪电符号,点它! 然后下拉找到这个: 你要事先在代码里面添加Form1 ...

  8. R语言学习 第十一篇:日期和时间

    R语言的基础包中提供了三种基本类型用于处理日期和时间,Date用于处理日期,它不包括时间和时区信息:POSIXct/POSIXlt用于处理日期和时间,其中包括了日期.时间和时区信息.R内部在存储日期和 ...

  9. 搭建centos7的开发环境2-单机版Hadoop2.7.3配置

    最近公司准备升级spark环境,主要原因是生产环境的spark和hadoop版本都比较低,但是具体升级到何种版本还不确定,需要做进一步的测试分析.这个任务对于大数据开发环境配置有要求,这里记录一下配置 ...

  10. 第三方支付设计——自有账户支付

    笔者在上一篇blog<<第三方支付架构设计之-帐户体系>>中已经稍微全面的阐述了第三方支付架构设计中的账户体系,在该体系中,其实涉及了各种各样的账户:银行侧账户(包括用户在银行 ...