美文网首页
二、SpringBoot的配置

二、SpringBoot的配置

作者: 紫雨杰 | 来源:发表于2018-05-04 18:33 被阅读0次

1、SpringBoot的配置文件

①、SpringBoot默认有两个全局的配置文件,配置文件名是固定的;

       ● application.properties

       ● application.yml

②、配置文件的作用:
          因为SpringBoot在底层都给我们自动配置好了,所以使用配置文件可以修改SpringBoot自动配置的默认值;

③、YAML(YAML Ain't Markup Language):
                YAML A Markup Language:是一个标记语言
                YAML isn't Markup Language:不是一个标记语言;

   YAML:以数据为中心,比json、xml等更适合做配置文件;

2、MYAL语法

 ①、YAML基本语法

      – 使用缩进表示层级关系
      – 建议使用空格。
      – 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
      – 大小写敏感

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

 ②、YAML 支持的三种数据结构

      – 字面量:单个的、不可再分的值
      – 对象:键值对的集合
      – 数组:一组按次序排列的值


 ③、YAML三种数据结构常用写法

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

        ● k:(空格)v  -> 字面量直接来写;   【字符串默认不用加上单引号或者双引号】

        ● 如果要加引号,单引号和双引号的区别:
               
              △ "" :双引号,不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思

                     例如:name: "zhangsan \n lisi":输出;zhangsan 换行 lisi

              △ '' :单引号,会转义特殊字符,特殊字符最终只是一个普通的字符串数据

                     例如:name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi

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

        ● k:(空格)v  -> 对象名,在下一行来写对象的属性和值的关系,注意缩进   【对象还是k: v的方式】

                    例如:
                            friends:
                                lastName: zhangsan
                                age: 20

        ● 还有一种行内写法:
       
                            friends: {lastName: zhangsan,age: 18}

    ▲ 数组(List、Set)

        ● 用-(空格) 值表示数组中的一个元素

                    例如:
                            pets:
                                ‐ cat
                                ‐ dog
                                ‐ pig

        ● 还有一种行内写法:
                            pets: [cat,dog,pig]

3、配置文件值注入到相应的JavaBean中

 ①、属性名匹配规则(Relaxed binding)

        – person.firstName:张三
        – person.first-name:张三
        – person.first_name:张三

        以上三种方式等价,作用是一样的

 ②、配置文件:
              person:
                username: hello
                age: 18
                boss: false
                birth: 2017/12/12
                maps: {k1: v1,k2: 12}
                lists:
                  ‐ lisi
                  ‐ zhaoliu
                dog:
                  name: 小狗
                  age: 12

★ 只需在对应的JavaBean上添加 @Component 注解 和 @ConfigurationProperties(prefix = "") 注解 即可完成配置文件值注入

        例如:

               /**
                * 将配置文件中配置的每一个属性的值,映射到这个组件中
                *
                * 1、@ConfigurationProperties : 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
                *
                * 2、prefix = "person":配置文件中哪个下面的所有属性进行一一映射;
                *
                * 3、只有这个组件是容器中的组件,才能容器提供的 @ConfigurationProperties 功能,所以需要添加 @Component 注解;
                */
               @Getter
               @Setter
               @ToString
               @Component
               @ConfigurationProperties(prefix = "person")
               public class Person {
                   private String username;
                   private Integer age;
                   private Boolean boss;
                   private Date birth;

                   private Map<String, Object> maps;
                   private List<Object> lists;
                   private Dog dog;
               }

★ 也可以使用Spring 底层的注解 @Value() 来获取配置文件中的值

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

                                  @ConfigurationProperties                                     @Value

          功能                       批量注入配置文件中的属性                                      一个个指定
         松散绑定(松散语法)                 支持                                                    不支持
          SpEL                          不支持                                                     支持
       JSR303数据校验                      支持                                                    不支持
        复杂类型封装                       支持                                                     不支持


  ▲ 无论配置文件是yml还是properties,@Value 和 @ConfigurationProperties都能获取到值;

  ▲ 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;

  ▲ 如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;

④、配置文件注入值数据校验

          /**
           * 将配置文件中配置的每一个属性的值,映射到这个组件中
           *
           * 1、@ConfigurationProperties : 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
           *
           * 2、prefix = "person":配置文件中哪个下面的所有属性进行一一映射;
           *
           * 3、只有这个组件是容器中的组件,才能容器提供的 @ConfigurationProperties 功能,所以需要添加 @Component 注解;
           *
           * 4、还可以使用Spring 底层的注解 @Value 来获取值
           *
           * 5、@ConfigurationProperties(prefix = "") 默认从全局配置文件中获取值;
           */
          @Getter
          @Setter
          @ToString
          @Component
          @ConfigurationProperties(prefix = "person")
          @Validated
          public class Person {

              /**
               * <bean class="Person">
               * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}">                            </property>
               * <bean/>
               */

              //@Value("${person.last-name}")
              private String lastName;

              //@Value("#{10 * 2}")
              private Integer age;

              /**
               *  1、@NotEmpty 是javax.validation.constraints下的
               *  2、@Value() 不支持JSR303校验
               */
              @NotEmpty   
              //@Value("true")
              //@Value("")
              private Boolean boss;
              private Date birth;

              /**
               * 1、@Value("${person.maps}") : 会报错
               *
               * 2、@Value() 不支持复杂的类型封装
               */
              private Map<String, Object> maps;
              private List<Object> lists;
              private Dog dog;
          }

★ properties配置文件在idea中默认utf-8可能会乱码,因为IDEA使用的是utf-8编码,而properties使用的是ASCII

解决properties配置文件在idea中乱码问题.png

4、@PropertySource & @ImportResource & @Bean

①、 @PropertySource:加载指定的配置文件;

          @Component
          @ConfigurationProperties(prefix = "person")     
          @PropertySource(value = {"classpath:person.properties"})
          public class Person {

    【注意】:
          1、使用 @PropertySource:加载指定的配置文件时,需要写  @ConfigurationProperties(prefix = "person") 注解,
          并且使用prefix指定是配置文件中哪个下面的所有属性,否则获取不到属性值

          2、如果指定的配置文件和本身自带的配置文件中都存在值,会优先使用本身自带的配置文件中的值,互补配置

②、@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;

    ● Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;

    ●  想让Spring的配置文件生效,加载进来,需要把 @ImportResource 注解标注在一个配置类【标注有@Configuration注解的类】上

         例如 :  
                  @ImportResource(locations = {"classpath:beans.xml"})
                  @Configuration
                  public class HelloService {

★ SpringBoot推荐给容器中添加组件的方式:推荐使用全注解的方式,而不是编写Spring的配置文件

    ●  配置类 @Configuration  相当于  Spring配置文件

    ●  使用 @Bean 给容器中添加组件

          /**
           * 1、@Configuration:指明当前类是一个配置类,就是来代替之前的Spring配置文件
           *
           * 2、在配置文件中用<bean><bean/>标签添加组件
           */
          @Configuration
          public class MyAppConfig {

              //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
              @Bean
              public HelloService helloService() {
                 System.out.println("使用 @Bean 注解给springboot 容器添加组件了");
                  return new HelloService();
              }
          }

5、配置文件占位符

①、配置文件中可以使用随机数

      ${random.value}、${random.int}、${random.long}
      ${random.int(10)}、${random.int[1024,65536]}

②、占位符获取之前配置的值,如果没有可以是用:指定默认值

      – 可以在配置文件中引用前面配置过的属性(优先级前面配置过的这里都能用)。
      – ${app.name:默认值}来指定找不到属性时的默认值

     例如:
           person.last-name=里斯+${random.uuid}
           person.age=${random.int}
           person.dog.name=${person.last-name}_dog
           person.dog.age=${person.myAge:12}   //如果person中没有myAge属性时,就用默认值12

  【注意】:
        如果没有配置person.last-name属性和值,而这个属性又是类中有的属性,然后使用 person.dog.name=${person.last-name}_dog 或者 
        person.dog.name=${person.last-name:tom}_dog 都会报错

6、Profile

▲ Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活指定参数等方式快速切换环境

①、多profile文件形式
      ● 在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml

      ● 默认使用application.properties的配置;

②、yml支持多文档块方式

          server:
            port: 8081
          spring:
            profiles:
              active: dev  #指定激活哪个环境
          ---

          server:
            port: 8082
          spring:
            profiles: dev

          ---
          server:
            port: 8083
          spring:
            profiles: prod   #指定属于哪个环境

③、激活指定profile的方式

      ● 1、在配置文件中指定 spring.profiles.active=dev

      ● 2、命令行:--spring.profiles.active=dev

              java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
              可以直接在测试的时候,配置传入命令行参数

      ● 3、虚拟机参数: -Dspring.profiles.active=dev
激活profile的方式.png

7、配置文件加载位置

 ①、spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件

        – file:./config/
        – file:./
        – classpath:/config/
        – classpath:/

      ● 以上是按照优先级从高到低的顺序,所有位置的文件都会被加载【互补配置】,高优先级配置内容会覆盖低优先级配置内容

 ②、还可以通过spring.config.location来改变默认的配置文件位置

      ● 项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;
        指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;

    例如:
        java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties

   【注意】:
        spring.config.location=D:/BaiduNetdiskDownload/application.properties 写在配置文件中不起作用

8、外部配置加载顺序

①、SpringBoot也可以从以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置

      ● 1.命令行参数
            所有的配置都可以在命令行上进行指定,多个配置用空格分开: --配置项=值

          例如:
            java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.servlet.context-path=/abc
  
        2.来自java:comp/env的JNDI属性
        3.Java系统属性(System.getProperties())
        4.操作系统环境变量
        5.RandomValuePropertySource配置的random.*属性值

   ▲  由jar包外向jar包内进行寻找;优先加载带profile

      ● 6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
      ● 7.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件

   ▲  再来加载不带profile

      ● 8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件
      ● 9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件

        10.@Configuration注解类上的@PropertySource
        11.通过SpringApplication.setDefaultProperties指定的默认属性

②、所有支持的配置加载来源 --> 参考Springboot的官方文档第四部分Externalized Configuration

  【链接】:https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#boot-features-external-config

9、自动配置原理

★ 配置文件到底能写什么?怎么写?

     ▲ 方式一:可以参考SpringBoot的官方文档

    【链接】 https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#common-application-properties

     ▲ 方式二:熟悉SpringBoot的自动配置原理,

        1)、SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration

        2)、@EnableAutoConfiguration 作用:利用AutoConfigurationImportSelector给容器中导入一些组件
    
           ●  可以查看selectImports()方法的内容;
                    List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置

           ●  SpringFactoriesLoader.loadFactoryNames():
                    扫描所有jar包类路径下 META‐INF/spring.factories
                    把扫描到的这些文件的内容包装成properties对象
                    从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
   
  【总结】:
        将类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;

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

        3)、每一个自动配置类进行自动配置功能;

        4)、以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;

                @Configuration //表示这是一个配置类,和以前编写的配置文件一样,可以给容器中添加组件

                //启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;
                // 并把HttpEncodingProperties加入到ioc容器中
                @EnableConfigurationProperties(HttpEncodingProperties.class) 
                          

                //Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效;
                @ConditionalOnWebApplication    // 判断当前应用是否是web应用,如果是,当前配置类生效   

                //判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;                                     
                @ConditionalOnClass(CharacterEncodingFilter.class) 

                //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
                //matchIfMissing = true:即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
                @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)                   
                public class HttpEncodingAutoConfiguration {

                //它已经和SpringBoot的配置文件映射了
                private final HttpEncodingProperties properties;

                //只有一个有参构造器的情况下,参数的值就会从容器中拿
                public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
                    this.properties = properties;
                }

                @Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
                @ConditionalOnMissingBean(CharacterEncodingFilter.class) //判断容器中如果没有这个组件,则把这个组件添加到容器中
                public CharacterEncodingFilter characterEncodingFilter() {
                    CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
                    filter.setEncoding(this.properties.getCharset().name());
                    filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
                    filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
                    return filter;
                }

    根据当前不同的条件判断,决定这个配置类是否生效?一但这个配置类生效;这个配置类就会给容器中添加各种组件;
    这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

        5)、所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;配置文件能配置什么就可以参照某个功能对应的这个属性类

              @ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值和bean的属性进行绑定
              public class HttpEncodingProperties {
              public static final Charset DEFAULT_CHARSET = Charset.forName("UTF‐8");

★ 精髓:
    1)、SpringBoot启动会加载大量的自动配置类
    2)、看我们需要的功能有没有SpringBoot默认写好的自动配置类;
    3)、再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
    4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值;

★ 通用模式
      – xxxAutoConfiguration:自动配置类
      – xxxProperties:属性配置类
      – yml/properties:文件中能配置的值就来源于[属性配置类]

10、查看详细的自动配置报告

    在配置文件中配置: debug=true 默认是false , 可以在控制台打印自动配置报告,查看当前应用哪些自动配置起作用了,哪些没有起作用

11、@Conditional扩展

      举例:
            @ConditionalOnBean 如果容器中存在指定的Bean,则满足条件执行,否则不满足条件;

            @ConditionalOnMissingBean 如果容器中不存在指定Bean,则满足条件执行,否则不满足条件;

相关文章

网友评论

      本文标题:二、SpringBoot的配置

      本文链接:https://www.haomeiwen.com/subject/mtzdlftx.html