Spring Boot自动配置原理分析
2018-03-24 09:45
639 查看
一、写在前面
随着时间的迁移Spring Boot 越来越多的出现在Java 后端程序员的视野中,Spring Boot 之所以会那么流行,很大的一个原因是自身集成了很多的Bean,简化了传统Sring 项目琐碎的文件配置。这些自动配置的Bean 在入口类启动的时候完成注入,并由Spring 的IoC 容器管理。所以在使用某些Bean的时候,不需要再由我们自动配置。下面我们就通过源码的方式来看看Spring Boot 是如何实现自动配置的。二、查看自动配置的Bean
我们可以在Spring Boot 项目的配置文件(application.properties,
application.yml)中设置一个属性
debug=true,设置完成后再启动Spring Boot 的入口类,就会在控制台输出有哪些Bean 已经完成了自动配置。
简单的截了一些如下图:
三、自动配置的原理分析
1.我们从入口类开始分析,我们都知道Spring Boot 项目一般会有一个入口类,这个入口类有一个很重要的特征就是加上了@SpringBootApplication注解。
@SpringBootApplication是一个组合注解,如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
其中有一个重要的注解
@EnableAutoConfiguration,这个注解的作用就是用于启用Spring Boot 的自动配置。
2.接着具体查看
@EnableAutoConfiguration,其实它也是一个组合注解,如下:
@SuppressWarnings("deprecation") @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class)
有一个注解
@Import(EnableAutoConfigurationImportSelector.class),在这个注解中有一个导入自动配置的选择器,用于导入自动配置的Bean。下面就来分析这个
EnableAutoConfigurationImportSelector都做了些什么。
3.
EnableAutoConfigurationImportSelector类继承自
AutoConfigurationImportSelector,在这个类中只有一个方法,用于判断是否启动了自动配置。
@Deprecated public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector { @Override protected boolean isEnabled(AnnotationMetadata metadata) { if (getClass().equals(EnableAutoConfigurationImportSelector.class)) { return getEnvironment().getProperty( EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true); } return true; } }
那么我们就来看看它的父类
AutoConfigurationImportSelector。
4.在
AutoConfigurationImportSelector类中有一个
selectImports()方法,如下:
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); // 用于获取自动配置的相关信息 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); configurations = sort(configurations, autoConfigurationMetadata); /** * 获得移除的自动配置信息 * 如果我们不想让Spring Boot 自动配置一些Bean, 我们可以使用在入口类的注解中使用exclude 声明 * 比如:@SpringBootApplication(exclude = {DispatcherServlet.class}) */ Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }
我们主要查看上面方法中的
getCandidateConfigurations(annotationMetadata, attributes)方法,
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 调用SpringFactoriesLoader 的loadFactoryNames() 方法,返回从类路径下获得自动配置相关的信息 List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); // 判断自动配置的信息是否为空,为空抛出异常,第二个参数为抛出的异常信息 Asser 4000 t.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<?> factoryClass, ClassLoader classLoader) { // factoryClass = EnableAutoConfiguration.class,可以通过上一步查看 String factoryClassName = factoryClass.getName(); try { /** * FACTORIES_RESOURCE_LOCATION 是一个编译器期量值为:"META-INF/spring.factories" * 用于获得所有jar 包类路径下的META-INF下的spring.factories 文件的URL */ Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); // 将扫面到文件中的内容包装成一个Properties 对象 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); /** * 获取EnableAutoConfiguration 类名在properties 中的值 * 这些值对应的Bean 就是要添加到Spring 容器中的自动配置类 */ String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
到这里就可知道Spring Boot 是如何实现自动配置的了,Spring Boot 会扫描到类路径下的
META-INF/spring.factories配置文件,把
EnableAutoConfiguration对应的的Bean值添加到容器中。
5.接着我们就来看一下类路径下
META-INF/spring.factories配置文件,其中
EnableAutoConfiguration对应的值都是有哪些。
下面是
spring.factories配置文件中
EnableAutoConfiguration对应的值,为了显示的效果在这里只贴出一部分。我们可以发现一个规律,这些值一般都是以×××AutoConfiguration命名,每一个×××AutoConfiguration 都作为容器中的一个组件,被添加到IoC 容器中,从而实现Spring Boot 的自动配置。
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,\
四、总结
这篇博文简单的分析了Spring Boot 自动配置的原理,给大家提供一个参考的方向,关于其中的一些具体细节,大家可以自己查看底层的源码进行了解,希望本篇博文能够为你提供帮助。相关文章推荐
- Spring boot实战中自动配置原理分析
- spring boot实战(第十三篇)自动配置原理分析
- spring boot实战(第十三篇)自动配置原理分析
- SpringBoot启动及自动配置原理(注解)分析
- spring boot实战(第十三篇)自动配置原理分析
- 【Spring Boot 系列 自动配置原理分析】
- VisualVM jvm gc调优_安装_原理_配置_集成_日志_验证_分析
- CodeIgniter配置之autoload.php自动加载用法分析
- IPv6无状态地址自动配置机制分析
- ScrollView(RecyclerView等)自动滚动原理分析,还有阻止自动滑动的解决方案 ... http://www.apkbus.com/blog-945380-76974.html
- Hadoop2.7.1配置NameNode+ResourceManager高可用原理分析
- JAVAEE——SpringBoot配置篇:配置文件、YAML语法、文件值注入、加载位置与顺序、自动配置原理
- Spring Boot核心原理-自动配置
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]
- SpringBoot自动配置的简单分析
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]
- 全面解析SpringBoot自动配置的实现原理
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]
- Spring Boot 运行原理 - 查看Spring Boot自动配置项
- PGA自动管理原理深入分析及性能调整