SpringBoot核心原理之自动配置

从@SpringBootApplication注解入手

为了揭开SpringBoot的奥秘,我们直接从Annotation入手,看看@SpringBootApplication里面,做了什么?
打开@SpringBootApplication这个注解,可以看到它实际上是一个复合注解

 1 @Target(ElementType.TYPE)
 3 @Retention(RetentionPolicy.RUNTIME)
 5 @Documented
 7 @Inherited
 9 @SpringBootConfiguration //实际上是 @Configuration
11 @EnableAutoConfiguration
13 @ComponentScan(excludeFilters = {
15 @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
17 @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
19 public @interface SpringBootApplication {

SpringBootApplication 本质上是由 3 个注解组成,分别是

@Configuration
@EnableAutoConfiguration
@ComponentScan

我们直接用这三个注解也可以启动 springboot 应用,只是每次配置三个注解比较繁琐,所以直接用一个复合注解更方便些。

然后仔细观察这三个注解,除了 @EnableAutoConfiguration 可能稍微陌生一点,其他两个注解使用得都很多。

简单分析@Configuration

@Configuration这个注解大家应该有用过,它是JavaConfig形式的基于Spring IOC容器的配置类使用的一种注解。

因 为 SpringBoot 本质上就是一个 spring 应用,所以通过这 个注解来加载 IOC 容器的配置是很正常的。所以在启动类里面标注了@Configuration,意味着它其实也是一个 IoC 容器的配置类。

传统意义上的 spring 应用都是基于xml 形式来配置 bean 的依赖关系,然后在spring 容器启动的时候,把 bean 进行初始化,如果 bean 之间存在依赖关系,则分析这些已经在 IoC 容器中的 bean 根据依赖关系进行组装。

直到 Java5 中,引入了 Annotations 这个特性,Spring 框架也紧随大流并且推出了基于 Java 代码和 Annotation 元 信息的依赖关系绑定描述的方式,也就是 JavaConfig。

从 spring3 开始,spring 就支持了两种 bean 的配置方式,一种是基于 xml 文件方式、另一种就是 JavaConfig。 任何一个标注了@Configuration 的 Java 类定义都是一个 JavaConfig 配置类。

在这个配置类中,任何标注了 @Bean 的方法,它的返回值都会作为 Bean 定义注册到 Spring 的 IOC 容器,方法名默认成为这个 bean 的 id。

简单分析@ComponentScan

@ComponentScan 这个注解是大家接触得最多的了,相当于xml 配置文件中的
<context:component-scan>。

它的主要作用就是扫描指定路径下的标识了需要装配的类,自动装配到 spring 的 Ioc 容器中。 标识需要装配的类的形式主要是:@Component、 @Repository、@Service、@Controller这类的注解标识的类。

ComponentScan默认会扫描当前 package 下的的所有加了相关注解标识的类到 IoC 容器中;

深入分析@EnableAutoConfiguration

我们把@EnableAutoConfiguration 放在最后讲的目的并不是说它是一个新的东西,只是他对于springboot来说意义重大。

EnableAutoConfiguration的主要作用其实就是帮助springboot应用把所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器中。

Enable并不是新鲜玩意

在spring3.1版本中,提供了一系列@Enable 开头的注解,Enable注解应该是在 JavaConfig 框架上更进一步的完善,用户在使用 spring 相关的框架时,避免配置大量的代码从而降低使用难度。

比如常见的一些Enable注解:@EnableWebMvc,(这个注解引入了MVC框架在Spring应用中需要用到的所有bean); 比如说@EnableScheduling,开启计划任务的支持。

找到 EnableAutoConfiguration,我们可以看到每一个涉及到Enable开头的注解,都会带有一个@Import 的注解。

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

@Import注解

import注解是什么意思呢? 联想到 xml 形式下有一个 形式的注解,就明白它的作用了。 import 就是把多个分来的容器配置合并在一个配置中。在 JavaConfig 中所表达的意义是一样的。

@Import 注解可以配置三种不同的class

基于普通bean或者带有@Configuration的bean进行注入;
实现 ImportSelector 接口进行动态注入;
实现 ImportBeanDefinitionRegistrar 接口进行动态注入;
分析@Import(AutoConfigurationImportSelector.class)
了解ImportSelector和ImportBeanDefinitionRegistrar 后,对于EnableAutoConfiguration的理解就容易一些了,它会通过 import 导入第三方提供的 bean 的配置类: @Import(AutoConfigurationImportSelector.class)

从名字来看,可以猜到它是基于 ImportSelector 来实现基于动态 bean 的加载功能。

之前我们讲过 Springboot @Enable*注解的工作原理 ImportSelector接口selectImports 返回的数组(类的全类名)都会被纳入到spring容器中。 那么可以猜想到这里的实现原理也一定是一样的,定位到AutoConfigurationImportSelector这个类中的selectImports方法。

1 public String[] selectImports(AnnotationMetadata annotationMetadata) {
2         if (!this.isEnabled(annotationMetadata)) {
3             return NO_IMPORTS;
4         } else {
5             AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
6             AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
7             return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
8         }
9     }

定位到 AutoConfigurationMetadataLoader.loadMetadata代码,可以看到加载了"META-INF/spring-autoconfigure-metadata.properties";



1 final class AutoConfigurationMetadataLoader {
2 protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";
3
4 private AutoConfigurationMetadataLoader() {
5 }
6
7 public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
8     return loadMetadata(classLoader, PATH);
9 }

定位到this.getAutoConfigurationEntry->getCandidateConfigurations,可以看到用到SpringFactoriesLoader;

1 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
2      List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
3              getBeanClassLoader());
4      Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
5              + "are using a custom packaging, make sure that file is correct.");
6      return configurations;
7  }

本质上来说,其实EnableAutoConfiguration会帮助springboot应用把所有符合@Configuration配置都加载到当前SpringBoot创建的IoC容器,而这里面借助了Spring框架提供的一个工具类SpringFactoriesLoader的支持,以及用到了Spring提供的条件注解 @Conditional,选择性的针对需要加载的bean进行条件过滤

SpringFactoriesLoader

SpringFactoriesLoader的作用是从 classpath/META-INF/spring.factories 文件中,根据 key 来加载对应的类到spring IoC容器中。

定位到SpringFactoriesLoader.loadSpringFactories源码,可以看到加载了"META-INF/spring.factories"。

1 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
2         MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
3         if (result != null) {
4             return result;
5         } else {
6             try {
7                 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
8                 LinkedMultiValueMap result = new LinkedMultiValueMap();

它其实和java中的SPI机制的原理是一样的,不过它比SPI更好的点在于不会一次性加载所有的类,而是根据 key进行加载。

例如:dubbo-spring-boot-starter-2.0.0.jar!/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.alibaba.dubbo.spring.boot.DubboAutoConfiguration,com.alibaba.dubbo.spring.boot.DubboProviderAutoConfiguration,com.alibaba.dubbo.spring.boot.DubboConsumerAutoConfiguration

条件过滤Conditional

在分析AutoConfigurationImportSelector的源码时看到,会先扫描 spring-autoconfiguration-metadata.properties 文件,最后再扫描spring.factories对应的类时,会结合前面的元数据进行过滤,为什么要过滤呢? 原因是很多的@Configuration 其实是依托于其他的框架来加载的,如果当前的classpath环境下没有相关联的依赖,则意味着这些类没必要进行加载,所以,通过这种条件过滤可以有效的减少@configuration类的数量从而降低 SpringBoot 的启动时间。

原文地址:https://www.cnblogs.com/xingxin666/p/11625566.html

时间: 2024-10-07 18:49:54

SpringBoot核心原理之自动配置的相关文章

SpringBoot是如何实现自动配置的?--SpringBoot源码(四)

注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三) 温故而知新,我们来简单回顾一下上篇的内容,上一篇我们分析了SpringBoot的条件注解@ConditionalOnXxx的相关源码,现挑重点总结如下: SpringBoot的所有@ConditionalOnXxx的条件类OnXxxCondition都是继承于SpringBootCondition

基于springboot的多数据源自动配置实现

最近做了一个自动支持多数据源配置的功能,基于springboot生态扩展,可自动识别配置文件中的数据库配置参数,并进行autoconfig. multiple-datasource多数据源支持模块 功能性 支持自动化配置多个数据源: 支持自动化配置持久层框架(mybatis): 支持自动化配置分布式事务管理器(JTA-Atomikos): 支持不同数据源使用不同数据库: 支持不同数据源使用不同数据库且使用不同连接池(hikari.dbcp2.tomcat-pool.druid等): 支持自动适配

SpringBoot嵌入式Tomcat的自动配置原理

在读本篇文章之前如果你读过这篇文章SpringBoot自动装配原理解析应该会更加轻松 准备工作 我们知道SpringBoot的自动装配的秘密在org.springframework.boot.autoconfigure包下的spring.factories文件中,而嵌入Tomcat的原理就在这个文件中加载的一个配置类:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguratio

面试题: SpringBoot 的自动配置原理及定制starter

3.Spring Boot 的自动配置原理 package com.mmall; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] ar

Springboot学习~7:SpringMVC自动配置

Spring MVC auto-configuration Spring Boot 自动配置好了SpringMVC 以下是SpringBoot对SpringMVC的默认配置:==(WebMvcAutoConfiguration)== Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans. 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转

助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoo

注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接如何分析SpringBoot源码模块及结构?--SpringBoot源码(二) 上一篇分析了SpringBoot源码结构及各个模块pom之间的关系后,那么此篇开始就开始解开SpringBoot新特性之一--自动配置的神秘面纱了.因为SpringBoot自动配置原理是基于其大量的条件注解ConditionalOnXXX,因此,本节我们先来撸下Spring的条件注解的相关源码. 2 SpringBoot的派生条件

SpringBoot源码分析----(一)SpringBoot自动配置

前言 springboot项目将模块化设计发挥到及至,需要什么模块,只需导入这个模块对应的stater即可,当然,用户根据业务需要自定义相关的stater,关于自定义stater在后续章节将一一解说,学习springboot,首要了解springboot的自动配置原理,我们从springboot项目的主启动类说起逐步解读springboot自动配置的奥秘. springboot自动配置解读 @SpringBootApplication public class SpringBootQuickAp

008 WEBmvc的自动配置

一 .概述 在springboot之中开发一个web项目是十分的简单的,我们本节就看一下springboot之中mvc的自动配置原理,这样可以帮助我们在后面覆盖springboot的默认的配置信息. 二 .springboot的mvc自动配置 下面就是springboot的webMVC的自动配置类,我们首先分析一下主要的结构问题. @Configuration @ConditionalOnWebApplication @ConditionalOnClass({ Servlet.class, Di

7、springmvc的自动配置

1.springmvc的自动配置 文档:https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-spring-mvc WebMvcAutoConfiguration.java Spring Boot 自动配置好了SpringMVC 以下是SpringBoot对SpringMVC的默认配置:(WebMvcAutoConfiguration) * Inclusion of Co