Spring Boot 2.x实战16 - 深入Spring Boot 1 - Spring Boot自动配置的魔法原理

1 Spring Boot介绍

Spring Boot给我们提供了快速创建生产级别Spring应用的能力,Spring Boot可以根据应用中包含的不同的库对其进行自动配置,而我们开发Spring Boot应用只需要极少的配置,这让我们在研发过程中将主要的精力集中到业务开发,而不会在技术相关的配置上花费过多的时间。

我们新建一个Spring Boot项目作为本章的演示:

应用信息:

Grouptop.wisely

Artifactspring-boot-in-depth

DependenciesSpring Web Starter

2 Spring Boot的魔法

Spring Boot的魔法来源于自动配置,我们这节的内容就是探讨自动配置的魔法是如何实现的。

2.1 加载自动配置

首先,Spring Boot的入口类是一个简单的包含可执行main()方法的Java类,如:

@SpringBootApplication 
public class SpringBootInDepthApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootInDepthApplication.class, args);
   }

}

这个类有两个我们不熟悉的东西,分别是:@SpringBootApplicationSpringApplication,我们相信Spring Boot的魔法一定来自这两个东西,@SpringBootApplicationSpringApplication都位于spring-boot-autoconfigure-2.2.x.RELEASE.jar中。

首先我们先看看SpringApplicationSpringApplication的作用是为为我们新建一个Spring IoC容器,它在非Web环境中为我们新建一个AnnotationConfigApplicationContext,Web环境中新建AnnotationConfigServletWebServerApplicationContext,响应式Web环境中新建AnnotationConfigReactiveWebServerApplicationContext,看来SpringApplication没有特别的神奇之处。

我们再看看@SpringBootApplication定义:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //1
@EnableAutoConfiguration //2
@ComponentScan(excludeFilters = {
      @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })//3
@ConfigurationPropertiesScan //4
public @interface SpringBootApplication {}
  1. 组合获得@SpringBootConfiguration注解的功能,而这个注解又组合@Configuration元注解,意味着入口类是一个配置类;
  2. @EnableAutoConfiguration开启自动配置,看来就是它了,我们前面也学过了@Enable*的原理,我们下一步再继续分析;
  3. 注解@ComponentScan获得自动扫描Bean的功能。
  4. 自动扫描标注了@ConfigurationProperties的类,并将它注册成Bean。

我们接着看@EnableAutoConfiguration的定义:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

如我们所料,和前面学习的一样,@Import注解导入一个自动配置选择器:AutoConfigurationImportSelector。我们首先聚焦AutoConfigurationImportSelector所实现的接口ImportSelector的重载方法selectImports,整体的调用流程如下:

  • getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata):获得应导入的自动配置;

  • getCandidateConfigurations(annotationMetadata,attributes):获得自动配置类的名称;

  • SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()):从类路径下获取所有META-INF/spring.factories(如spring-boot-autoconfigure-2.2.x.RELEASE.jar/META-INF/spring.factories)文件,并查找类型为getSpringFactoriesLoaderFactoryClass()的工厂,即org.springframework.boot.autoconfigure.EnableAutoConfiguration,找到我们符合自动加载的配置为:

    通过上面的学习,我们知道了Spring Boot是如何加载自动配置类的,下面我们将讲解这些自动配置类是如何自动配置的。

2.2 如何自动配置

我们看一个最简单的自动配置类,来感受一下:

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
      AnnotatedElement.class }) 
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) 
public class AopAutoConfiguration {

   @Configuration
   @EnableAspectJAutoProxy(proxyTargetClass = false)
   @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
   public static class JdkDynamicAutoProxyConfiguration {

   }

   @Configuration
   @EnableAspectJAutoProxy(proxyTargetClass = true)
   @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
   public static class CglibAutoProxyConfiguration {

   }

}

我们不熟悉的注解包含@ConditionalOnClass@ConditionalOnProperty,而这两个注解用到了前面学习的两个基础知识:“条件注解@Conditional”和 “组合元注解”,以@ConditionalOnClass为例:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {}

@ConditionalOnClass代表的是@ConditionalOnClassCondition条件下的语义。我们通过语义即可知道该注解的功能,即检测特定的一些类是否都存在于类路径中,当这些类全存在的时候,被注解的类或方法才有效,如果不符合则可视被注解的类或方法不存在。

@ConditionalOnClass同类的条件注解有如下:

  • @ConditionalOnBean:只有在指定的一批Bean都已存在容器中有效;
  • @ConditionalOnMissingBean:只有在指定的一批Bean不存在于容器中才有效;
  • @ConditionalOnClass:只有在指定的一批类都在当前类路径中有效;
  • @ConditionalOnMissingClass:只有在指定的一批类都不在当前类路径中有效;
  • @ConditionalOnProperty:只有当前的配置属性符合条件时有效;
  • @ConditionalOnResource:只有指定的一批资源在类路径中有效;
  • @ConditionalOnExpression:只有Spring EL运算结果为true时有效;
  • @ConditionalOnJava:只有满足支持的Java版本才有效;
  • @ConditionalOnWebApplication:只有在Web应用时才有效;
  • @ConditionalOnNotWebApplication:只有在非Web应用时有效;
  • @ConditionalOnSingleCandidate:只有在指定的一批Bean在容器中已存在且只有一个候选Bean下才有效;
  • @ConditionalOnCloudPlatform:只在指定的云平台下有效。

配置文件之间如果有先后依赖顺序的话,我们可以用@AutoConfigureAfter@AutoConfigureBefore注解指定配置顺序,也可以通过@AutoConfigureOrder来指定优先级。

Spring Boot自带的自动配置位于spring-boot-autoconfigure-2.2.x.RELEASE.jarorg.springframework.boot.autoconfigure包下以AutoConfiguration结尾的都是自动配置类。

Spring Boot 2.x实战16 - 深入Spring Boot 1 - Spring Boot自动配置的魔法原理_第1张图片

Spring Boot提供的所有自动配置参见:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#auto-configuration-classes

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html

Spring Boot 2.x实战16 - 深入Spring Boot 1 - Spring Boot自动配置的魔法原理_第2张图片

主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和屁股里(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

你可能感兴趣的:(Spring,Boot2.x实战全集,Spring,Boot2.x实战,-,Spring,Boot,Spring魔法解密)