SpringBoot配置和自动配置原理

1. 配置介绍

        SpringBoot使用一个全局的配置文件 核心配置文件,配置文件名在约定的情况下 名字是固定的; 配置文件的作用:修改SpringBoot自动配置的默认值;SpringBoot在底层都给我们自动配置好;

        ∙application.properties        #最后加载,优先级最高

        ∙application.yml    #最常用,最先加载,优先级最低

        ∙application.yaml

YAML(YAML Ain't Markup Language)

YAML A Markup Language:是一个标记语言

YAML isn't Markup Language:不是一个标记语言;

2. 配置格式

        两种配置文件的格式 在springboot框架中,resource文件夹里可以存放配置的文件有两种:properties和yml。

        2.1 application.properties的用法:扁平的k/v格式。

server.port=8081
server.servlet.context‐path=/test

        2.2 application.yml的用法:树型结构。

server:
    port: 8088
        servlet:
            context‐path: /test

        建议使用后者,因为它的可读性更强。 可以看到要转换成YML我们只需把properies里按. 去拆分即可。

3. yml基本语法

        k:(空格)v:表示一对键值对(空格必须有);

        以空格的缩进来控制层级关系;

        只要是左对齐的一列数据,都是同一个层级的 属性和值也是大小写敏感;

        如果有特殊字符% & 记得用单引号(‘)包起来

4. 配置文件的加载顺序 

 <includes>
     <include>**/application*.yml</include>
     <include>**/application*.yaml</include>
     <include>**/application*.properties</include>
 </includes>

        加载顺序从上到下,由低到高

        如果同时存在不同后缀的文件按照这个顺序加载主配置文件;互补配置;

5. 外部约定配置文件加载顺序

        低↓

                1. classpath根目录下

                

                2. classpath根config/

                

                3. 项目根目录

                如果当前项目是继承/耦合 关系maven项目的话,项目根目录=父maven项目的根目录

                 

                 4. 项目根目录/config

                

                5. 直接子目录/config

1 java ‐jar configuration_file‐0.0.1‐SNAPSHOT.jar ‐‐spring.config.location=D:\config/

         高↓

         优先级由底到高,高优先级的配置会覆盖低优先级的配置;互补配置       

        官网:

1 optional:classpath:/
2 optional:classpath:/config/
3 optional:file:./
4 optional:file:./config/*/
5 optional:file:./config/
6 optional:classpath:custom‐config/ ‐‐spring.config.location
7 optional:file:./custom‐config/ ‐‐spring.config.location

6. Profile文件的加载

        Profile的意思是配置,对于应用程序来说,不同的环境需要不同的配置。 SpringBoot框架提供了多profile的管理功能,我们可以使用profile功能来区分不同环境的配置。

        1. 多Profile文件,Spring官方给出的语法规则是application-{profile}.properties(.yaml/.yml)。

        2.如果需要创建自定义的的properties文件时,可以用application-xxx.properties的命名方式

         如下图所示

        配置环境:spring.profiles.active=prod

         开发环境

        生产环境

 .        若我们需要在两种环境下进行切换,只需要在application.yml修改spring.profiles.active=prod值

1 先按照位置来读取优先级, 在同一位置下profile优先级最高, 如果没有指定profile, 先yml‐‐yaml‐‐properties

7. 所有配置文件顺序

        优先级从低到高

                1. 打包在jar中配置文件

                2. 打包在jar中profile

                3. 打包的jar之外的配置文件

                4. 打包的jar之外的profile

1 java ‐jar configuration_file‐0.0.1‐SNAPSHOT.jar
2
3 jar包之外的配置文件 yml‐‐>yaml‐‐>properties
4 optional:classpath:/config/ yml‐‐>yaml‐‐>properties
5 optional:classpath:/ yml‐‐>yaml‐‐>properties
6
7
1 java ‐jar configuration_file‐0.0.1‐SNAPSHOT.jar ‐‐spring.profiles.active=dev
2
3 jar包之外的配置文件 profile‐dev ‐‐> yml‐‐>yaml‐‐>properties
4 optional:classpath:/config/ profile‐dev ‐‐> yml‐‐>yaml‐‐>properties
5 optional:classpath:/ profile‐dev ‐‐> yml‐‐>yaml‐‐>properties
6
7
1 java ‐jar configuration_file‐0.0.1‐SNAPSHOT.jar ‐‐spring.config.location=D:/application.properties
2
3 优先级最大, 因为指定了具体的配置文件。 所以不会和默认的约定配置文件进行互补

8. 配置文件值注入

        字面量:普通的值(数字,字符串,布尔)

                1. k: v:字面直接来写;

                2. 字符串默认不用加上单引号或者双引号; "":双引号;

                3. 不会转义字符串里面的特殊字符;

                4. 特殊字符会作为本身想表示的意思 name: "zhangsan \n lisi":输出;zhangsan 换行 lisi '':单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据 name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi

        对象、Map(属性和值)(键值对):

#对象还是k: v的方式
1 friends:
2     lastName: zhangsan
3     age: 20

#行内写法:
1 friends: {lastName: zhangsan,age: 18}

        数组:

#用- 值表示数组中的一个元素
1 pets:
2 ‐ cat
3 ‐ dog
4 ‐ pig

#行内写法
1 pets: [cat,dog,pig]

        @Value获取值和@ConfigurationProperties获取值比较

        

         使用场景

                如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value; 如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;

        使用@PropertySource(value = {"classpath:person.properties"}) 加载指定的配置文件;

9. Spring Boot的配置和自动配置原理

常见应用程序属性 (spring.io)

        1. @SpringBootApplication

                Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot 需要运行这个类的main方法来启动SpringBoot应用;

        

1 @Target(ElementType.TYPE)  #设置当前注解可以标记在哪
2 @Retention(RetentionPolicy.RUNTIME) #当注解标注的类编译以什么方式保留             
                                      #RetentionPolicy.RUNTIME 会被jvm加载
3 @Documented    #java doc 会生成注解信息
4 @Inherited #是否会被继承
5 @SpringBootConfiguration #标注在某个类上,表示这是一个Spring Boot的配置类;内部                                
                                 使用了@Configuration
6 @EnableAutoConfiguration  #开启自动配置功能 告诉SpringBoot开启自动配置,会帮我们自动去加载 
                             自动配置类
7 @ComponentScan(excludeFilters = {   #扫描包
8 @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
9 @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

        2. @AutoConfigurationPackage

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage  #将当前配置类所在包保存在BasePackages的Bean中。供Spring内部使用
@Import({AutoConfigurationImportSelector.class})  #关键点
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

                1. @AutoConfigurationPackage

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class}) #保存扫描路径,提供给spring‐data‐jpa需要扫描@Entity

public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

        2. @Import(EnableAutoConfigurationImportSelector.class) 

                EnableAutoConfigurationImportSelector实现了DeferredImportSelector,内部在解析@Import时会去调用getAutoConfigurationEntry()方法,这个方法会去扫描具有META-INF/spring.factories的jar包

 protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

                spring.factories文件是Key=Value形式,多个Value时使用,隔开,该文件中定义了关于初始化,监听器等信息,而真正使自动配置生效的key是
org.springframework.boot.autoconfigure.EnableAutoConfiguration :上图

每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;

所有的自动配置类

Auto-configuration Classes (spring.io)

        3. 每一个自动配置类进行自动配置功能

                @EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在 SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的 class,然后将所有自动配置类加载到Spring容器中

10. 以HttpEncodingAutoConfiguration为例解释自动配置原理

        1. 源码


@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled",             
                              matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    private final Encoding properties;

public HttpEncodingAutoConfiguration(ServerProperties properties) {
    this.properties = properties.getServlet().getEncoding();
}

@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
    filter.setEncoding(this.properties.getCharset().name());
    filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
    filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
    return filter;
}

        @Configuration(proxyBeanMethods = false)

                标记了@Configuration Spring底层会给配置创建cglib动态代理。 作用:就是防止每次调用本类的Bean方法而重新创建对 象,Bean是默认单例的,优先从ioc容器中获取bean对象

        @EnableConfigurationProperties(ServerProperties.class)

                启用可以在配置类设置的属性对应的类


@ConfigurationProperties(
    prefix = "server",
    ignoreUnknownFields = true
)
public class ServerProperties {
    private Integer port;
    private InetAddress address;
    @NestedConfigurationProperty
    private final ErrorProperties error = new ErrorProperties();
    private ServerProperties.ForwardHeadersStrategy forwardHeadersStrategy;
    private String serverHeader;
    private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L);
    private Shutdown shutdown;
    @NestedConfigurationProperty
    private Ssl ssl;
    @NestedConfigurationProperty
    private final Compression compression;
    @NestedConfigurationProperty
    private final Http2 http2;
    private final ServerProperties.Servlet servlet;
    private final ServerProperties.Reactive reactive;
    private final ServerProperties.Tomcat tomcat;
    private final ServerProperties.Jetty jetty;
    private final ServerProperties.Netty netty;
    private final ServerProperties.Undertow undertow;

        @Conditional派生注解

                作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;

     

         过滤器

public class HttpEncodingAutoConfiguration {
    private final Encoding properties;

    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }

    @Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
    }
        this.properties.getCharset().name  
        properties=properties.getServlet().getEncoding()

                上面类似于从配置文件读取 server.servelt.encoding.charset这个配置的值然后设置到filter中,内嵌的tomcat货拿到这个bean,最后实现自动配置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值