SpringBoot(11) —— 自动配置原理再理解

目录

    • 1.源码分析
    • 2.小结
    • 3.debug=true
    • 4.整体流程回顾


1.源码分析

  • 说到自动配置,就不得不说在第5篇博客中说到的springBoot的自动配置原理(SpringBoot(5) —— SpringBoot自动装配原理).),实现自动配置原理的重要文件就是"META-INF/spring.factories",这个文件中存储了几乎所有场景下的自动配置类

SpringBoot(11) —— 自动配置原理再理解_第1张图片

  • 我们在application.yml/prtperties中可以配置的东西和"META-INF/spring.factories"文件有莫大的关系

  • 我们可以在"META-INF/spring.factories"文件中找一个比较简单的自动配置类查看它的源码来分析二者的关系

  • 比如:org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration(我们只看这个自动配置类上标注它的注解+类定义)

    //表示这是一个配置类
    @Configuration(proxyBeanMethods = false)
    
    //EnableConfigurationProperties,启动配置属性
    @EnableConfigurationProperties(ServerProperties.class)
    
    //ConditionalOnXXX,这个配置类被加载到spring容器中的条件,这是spring的底层注解
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    @ConditionalOnClass(CharacterEncodingFilter.class)
    @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
    
    //类定义
    public class HttpEncodingAutoConfiguration {}
    
  • 从源码我们可以发现,和配置属性相关的就只有注解@EnableConfigurationProperties(ServerProperties.class),这个注解传入了一个class对象:ServerProperties.class

  • 我们点进这个类看一眼,只看标注这个类的注解、类定义+成员属性的定义

    @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
    public class ServerProperties {
    
    	/**
    	 * Server HTTP port.
    	 */
    	private Integer port;
    
    	/**
    	 * Network address to which the server should bind.
    	 */
    	private InetAddress address;
    
    	@NestedConfigurationProperty
    	private final ErrorProperties error = new ErrorProperties();
    
    	/**
    	 * Strategy for handling X-Forwarded-* headers.
    	 */
    	private ForwardHeadersStrategy forwardHeadersStrategy;
    
    	/**
    	 * Value to use for the Server response header (if empty, no header is sent).
    	 */
    	private String serverHeader;
    
    	/**
    	 * Maximum size of the HTTP message header.
    	 */
    	private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8);
    
    	/**
    	 * Type of shutdown that the server will support.
    	 */
    	private Shutdown shutdown = Shutdown.IMMEDIATE;
    
    	@NestedConfigurationProperty
    	private Ssl ssl;
    	}
    
  • 我们可以发现标注这个类的注解@ConfigurationProperties,我们在使用yml注入类属性的时候就使用过这个注解,这里在这个类上面使用@ConfigurationProperties,显然也就是在注入类的属性值,而注入的属性对应的对象在配置文件中的名称为server;在学习过yaml之后,我们知道对象可以在yaml配置文件中进行存储,并且设置对象的属性只需要通过对象名称.属性名称即可设置

  • 我们可以创建一个yaml文件,将server粘贴进去,再使用"."观察它可以设置的属性有哪些
    SpringBoot(11) —— 自动配置原理再理解_第2张图片
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 我们可以发现serverProperties类中的所有属性都可以通过"server."来进行配置

  • 所以我们可以初步猜测:我们在配置文件application.yml/properties中可以配置的东西就是这些XXXProperties类中的属性

  • 我们在来查看分析自动装配原理的时候看过的自动配置类WebMvcAutoConfiguration,对于这个类,它的@EnableConfigurationProperties注解并没有直接写在它的类声明上面,而是写在了它的一个内部类上面 —— WebMvcAutoConfigurationAdapter ,我们开看一下这个类上标注的注解+类定义

    	@Configuration(proxyBeanMethods = false)
    	@Import(EnableWebMvcConfiguration.class)
    	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
    	@Order(0)
    	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}
    
  • 我们可以发现注解@EnableConfigurationProperties,这个注解传入了两个类的class对象,我们先来看第一个WebMvcProperties

    @ConfigurationProperties(prefix = "spring.mvc")
    public class WebMvcProperties {}
    
  • 我们可以发现它使用了配置文件中的对象"spring.mvc"
    SpringBoot(11) —— 自动配置原理再理解_第3张图片
    SpringBoot(11) —— 自动配置原理再理解_第4张图片
    在这里插入图片描述

  • 可以发现,在配置文件中,我们可以使用spring.mvc来配置WenMvcProperties这个类中的所有成员属性的属性值

  • 所以,综合上面两个例子我们可以发现:我们可以在配置文件application.yml/properties中进行配置的东西,它都是对应的存在于某一个XXXproperties类的成员属性

  • 我们之所以可以通过配置文件来修改XXXproperties类的成员属性值,是因为这个类使用了注解@ConfigurationProperties,使用这个注解来自动注入成员属性值的时候,必须保障成员属性值的名称与其在配置文件中key保持一致,因为注解@ConfigurationProperties实现属性自动注入的底层实现还是调用的set()

  • 所以我们在XXXproperties类中看到的注解@ConfigurationProperties()的()中的字符串就是这个类对应在配置文件中存储的对象的名称


2.小结

  • 首先springBoot项目中必然存在一个总的配置文件(可能是yaml格式,也可能是其他格式),但是我现在还没找打在哪里,但是一定是存在的,这个文件存储了所有的配置参数的初始化/默认值
  • 首先springBoot项目中必然存在一个总的配置文件,我找到了它在哪里
    SpringBoot(11) —— 自动配置原理再理解_第5张图片
  • 比如我们找server.port
    SpringBoot(11) —— 自动配置原理再理解_第6张图片

SpringBoot(11) —— 自动配置原理再理解_第7张图片

  • 在项目启动的时候,各个自动配置类首先通过@ConditionalOnXXX的筛选,选出哪些自动配置类将会被装入spring容器,为容器添加组件

  • 每一个通过筛选被加载到spring容器中的自动配置类中如果需要配置参数,那么这个配置类的内部将会有一个XXXProperties对象属性,这个XXXProperties对象的成员属性就是当前这个场景/自动配置类在进行自动配置的时候要使用的参数

  • 而参数的值是由于XXXProperties类上使用了注解@ConfigurationProperties自动注入的,所以在获取这个XXXProperties类的对象的时候会自动的从配置文件中将这个属性的值注入了进去(所以我才说一定存在一个总的配置文件),但是这个参数的值对于我们来说是当前使用这个场景的默认值/初始值

  • 我们可以在springBoot项目的配置文件application.yml/properties中通过当前场景的XXXProperties类上的注解@ConfigurationProperties中写的对象的名称,通过对象名称.属性名称的方式个性化的为当前场景配置我们指定的值

  • 总的来说就是我们的配置文件application.yml/properties和XXXProperties类上的注解@ConfigurationProperties对应的配置文件,都绑定了这个场景对应的参数对象的属性的set方法,默认配置文件中的set方法会先调用,而application.yml/properties中的配置方法会后调用,这就使得我们配置的参数总是会覆盖原来这个场景的配置参数的默认值/初始值

  • 比如我们经常配置的tomcat的运行端口号server.port,我们可以点进去看一看
    SpringBoot(11) —— 自动配置原理再理解_第8张图片


一句话总结︰根据当前项目不同的条件(导入了哪些依赖)判断,决定哪些配置类将会生效,根据生效的配置类,再去从配置文件中获取配置类中参数类XXXProperties的成员变量对应的默认值

  • 一但这个配置类生效/作为一个装配类的条件都满足,这个配置类就会给容器中添加自己内部的 组件/作为配置类加载到容器中 为容器添加上自己这个配置类中的组件(一般就是要注册的bean),这些 组件/bean 的属性是从对应的properties类中获取的,properties类里面的每一个属性除了有自己的默认值之外,又是和我们项中的application配置文件绑定了的

  • 所有在配置文件中能配置的属性都是在xxxProperties类中封装了的属性,我们的配置文件能配置什么就可以参照当前要配置的场景的自动配置类xxxAutoConfiguration的参数类成员属性xxxProperties上的注解@ConfigurationProperties中写的对象名称是什么,然后按照这个对象名称.xxxProperties类中的属性名称,就可以覆盖对应的配置参数的默认值了


sprinBoot自动配置的精髓

  • xxxxAutoConfigurartion:自动配置类,给容器中添加组件
  • xxxxProperties:提供了xxxxAutoConfigurartion中组件/bean的初始化参数

3.debug=true

  • 用于开启springboot的调试类,只要在application中配置了这个参数,我们就可以在控制台中看到本次启动springBoot项目哪些自动配置类生效了,哪些没有生效,即日志消息
  • 输出的日志消息分3类
    • Positive matches:装入了spring中的自动配置类(ConditionalOnXXX满足)
    • Negative matches:没有装入spring中的自动配置类(ConditionalOnXXX不满足)
    • Unconditional classes:没有条件的类

4.整体流程回顾

SpringBoot(11) —— 自动配置原理再理解_第9张图片
SpringBoot(11) —— 自动配置原理再理解_第10张图片
SpringBoot(11) —— 自动配置原理再理解_第11张图片SpringBoot(11) —— 自动配置原理再理解_第12张图片
SpringBoot(11) —— 自动配置原理再理解_第13张图片
    验证成功!

你可能感兴趣的:(SpringBoot,spring,boot)