zoukankan      html  css  js  c++  java
  • Spring Boot 2.配置

    配置

    配置文件、加载顺序、配置原理
    代码地址
    ssh git@gitee.com:Ding_DangMao/learn-spring-bot.git

    1. 配置文件

    • Spring boot使用一个全局的配置文件,配置文件名是固定的
      application.properties
      application.yml

    • 配置文件放在 src/main/resources目录或者类路径/config下

    • 配置文件的作用: 修改 spring boot自动配置的默认值,spring boot在底层都给我们自动配置好

    • yaml (yaml ain't markup language)

      yaml a markup language: 是一个标记语言

      yaml isn't markup language: 不是一个标记语言

    • 标记语言:

      以前的配置文件;大多使用的是 xxx.xml文件;

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

      yaml :配置例子

      server
        port: 8081
      
      <server>
        <port>8081</port>
      </server>
      

    2. YAML 语法

    2.1 基本语法

    • k:(空格)v 表示一对键值对(空格必须有)
      空格的缩进来控制层级关系;只要是左对齐的一列数据,都是同一个层级的
      server
        prot: 8081
        path: /hello
      
      属性和值也是大小写敏感;

    2.2 值的写法

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

      k: v 字面直接来写

      • 字符串默认不用加上单引号,或者双引号

      • "":双引号,不会转义字符串里面的特殊字符;特殊字符会作为本身像表示的意思

        name: "zhangsan lisi" 输出:zhangsan 换行 lisi

      • '':单引号,会转义特殊字符,特殊字符最终只是一个普通的字符串数据
        name: "zhangsan lisi" 输出:zhangsan 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 配置文件值注入

    • 配置文件
      person:
        lastName: zhangsan
        age: 18
        boss: false
        birth: 2017/12/17
        map: {k1: v1,k2: 12}
        list:
          - lisi
          - zhaoliu
        dog:
          name: 小狗
          age: 2
      
    • Java组件
      /**
       * 将配文件中配置的每一个属性的值,映射到这个组件中
       * @ConfigurationProperties:告诉 Spring Boot将本类中的所有属性和配置文件中相关的配置进项绑定
       * ====> prefix = "person" 配置文件中那个下面的所有属性进行--映射
       * 只有这个组件是容器中的组件,才能使用容器中提供 @ConfigurationProperties的功能
       */
      @Component
      @ConfigurationProperties(prefix = "person")
      public class Person {
          private String lastName;
          private Integer age;
          private Boolean boss;
          private Date birth;
      
          private Map<String, Object> map;
          private List<Object> list;
          private Dog dog;
      }
      
    • 我们可以导入配置文件处理器,以后编写配置就有提示了
      <!--导入配置文件处理器,配置文件进行绑定就会有提示-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-configuration-processor</artifactId>
          <optional>true</optional>
      </dependency>
      

    测试:

    /*
     * spring boot 单元测试
     * <p>
     * 可以在测试期间很方便的类似编码一样进行自动注入等容器功能
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringBoot02ConfigApplicationTest {
        @Autowired
        Person person;
    
        @Test
        public void contextLoads() {
            System.out.println(person);
            //Person{lastName='zhangsan', age=18, boss=false, birth=Sun Dec 17 00:00:00 CST 2017,
            // map={k1=v1, k2=12}, list=[lisi, zhaoliu], dog=Dog{name='小狗', age=2}}
        }
    }
    

    3.1 properties配置文件在 idea中默认 utf-8可能会乱码

    image

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

    # @ConfigurationProperties @Value
    功能 批量注入配置文件中的属性 一个个指定
    松散绑定(松散语法) 支持 不支持
    SpEL 不支持 支持
    JSR303数据校验 支持 不支持
    • 属性名匹配规则(relaxed binding 松散绑定)

      • person.firstName:使用标准方式
      • person.first-name:大写用-
      • person.first_name:大写用_
      • PERSON_FIRST_NAME:
        推荐系统属性使用这种写法
    • 配置文件 yml还是 properties他们都能获取到值;

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

      如果是,我们专门编写一个 JavaBean来配给制文件进行映射,我们直接使用 @ConfigurationProperties

    3.3 配置文件注入数据校验

    @Validated //JSR303数据校验 注入值的时候进行校验
    @Component
    @ConfigurationProperties(prefix = "person")
    public class Person {
        /*
         * <bean>
         * <property name="lastName" value="字面量/${}从环境变量,配置文件中获取值/#{SpEL}"></property>
         * </bean>
         *
         * */
    //    @Value("${person.last-name}")
        @Email //lastName 必须是 邮箱格式
        private String lastName;
        //    @Value("#{11*2}")
        private Integer age;
        //    @Value("true")
        private Boolean boss;
        private Date birth;
    
        private Map<String, Object> map;
        private List<Object> list;
        private Dog dog;}
    

    3.4 @PropertySource & @ImportResource

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

      @PropertySource(value = {"classpath:person.properties"})
      //@Validated //JSR303数据校验 注入值的时候进行校验
      @Component
      @ConfigurationProperties(prefix = "person")
      public class Person {
          /*
           * <bean>
           * <property name="lastName" value="字面量/${}从环境变量,配置文件中获取值/#{SpEL}"></property>
           * </bean>
           *
           * */
      //    @Value("${person.last-name}")
      //    @Email //lastName 必须是 邮箱格式 //js303
          private String lastName;
          //    @Value("#{11*2}")  //SpEL 表达式语言
          private Integer age;
          //    @Value("true")
          private Boolean boss;
          private Date birth;
      
          private Map<String, Object> map;
          private List<Object> list;
          private Dog dog;}
      
    • @ImportResource;导入 Spring的配置文件,让配给制文件里面的内容生效
      spring boot里面没有 Spring的配置文件,我们自己编写的配置文件,也不能自动识别;想让 spring的配置文件生效,加载进来; @ImportResource标注在一个配置类上

      @ImportResource(locations = {"classpath:beans.xml"})
      //导入spring的配置文件让其生效
      

      不来编写 Spring配置文件

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <bean id="helloService" class="com.cainiao100.springboot.service.HelloService">
      
          </bean>
      </beans>
      
      • Spring Boot推荐给容器中添加组件的方式;推荐使用全注解的方式
        1. 配置类===>spring配置文件
        2. 使用 @Bean给容器中添加组件
        /**
         * @Configuration 指明当前类是一个配置类, 代替之前的 spring配置文件
         * 在配置文件中用 <bean></bean>标签添加组件
         */
        @Configuration //指明当前类是一个配置类,代替之前的 spring配置文件
        public class MyAppConfig {
        
            //将方法的返回值添加到容器中,容器中这个组件默认的id就是方法名
            @Bean
            public HelloService helloService() {
                System.out.println("配置类 @Bean给容器添加组件了");
                return new HelloService();
            }
        }
        

    4. 配置文件占位符

    4.1 随机数

    ${random.value} ${random.int}   ${random.long}
    ${random.init(10)}  ${random.int[1024.65536]}
    

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

    # 配置 person的值
    person.last-name=张三${random.uuid}
    person.age=${random.int}
    person.birth=2017/12/15
    person.boss=false
    person.map.k1=v1
    person.map.k2=14
    person.list=a,b,c
    person.dog.name=${person.hello:hello }_dog #如果没有 person.hello的值,则使用 hello
    person.dog.age=15
    # 使用 idea设置 properties文件的编码为 utf-8
    

    5. Profile

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

    5.1 多 Profile文件

    • 我们在主配置文件编写的时候,文件名是 application-{profile}.properties/yml
      默认使用 application.properties

    5.2 yml支持多文档块方式

    server:
      port: 8081
    spring:
      profiles:
        active: dev
    ---
    #开发环境
    server:
      port: 8083
    spring:
      profiles:
        active: dev
    ---
    #生产环境
    server:
      port: 8084
    spring:
      profiles: pord
    

    5.3 激活指定 profile

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

    2. 命令行
      --spring.profiles.active=dev
      image

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

    3. 虚拟机参数

      –Dspring.profiles.active=dev
      image

    6. 配置文件加载位置

    • spring boot启动会扫描一下位置的 application.properties或者 application.yml 或者spring boot的默认配置文件

      • file:./config/ (当前项目的config文件夹下)
      • file:./ (当前项目文件路径下)
      • classpath:/config/ (类路径下config文件下 )
      • classpath:/ (类路径下)

      以上是按照优先顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先配置内容,spring boot会从这四个位置全部加载主配置文件;互补配置

      我们也可以通过配置 spring.config.location来改变默认配置,项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置
      java -jar xxx.jar --spring.config.location=G:/application.properties

    7. 外部配置加载顺序

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

    Spring Boot 支持多种外部配置方式

    1. 命令行参数
      多个配置用空格分开: --配置项=值 --配置项=值
    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指定的默认属性

    8. 自动配置原理

    8.1自动配置原理

    1. spring boot启动的时候加载主配置类,开启了自动配置功能 @EncodingAutoConfiguration

    2. @EncodingAutoConfiguration 作用:

      • 利用@Import({EnableAutoConfigurationImportSelector.class}) 给容器中导入一些组件?

      • 可以查看 selectImports()方法的内容

      • List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置

        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        //扫描所有 jar包路径下 META-INF/spring.factories
        //把扫描到的这些文件的内容包装成 properties对象
        //从 properties中获取到 EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
        
        

        将类路径下 META-INF/spring.factories 里面配置所有 EnableAutoConfiguration的值加入到容器中

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

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

    4. 以 HttpEncodingAutoConfiguration(http编码自动配置) 为例解释自动配置原理

      @Configuration 
      //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
      @EnableConfigurationProperties({HttpEncodingProperties.class}) 
      //启动指定类的 ConfigurationProperties功能;将配置文件中对应的值和 
      //HttpEncodingProperties绑定起来;;并把 HrrpEncodingProperties加入到 ioc容器中
      @ConditionalOnWebApplication 
      //(判断当前应用是否是web应用,如果是当前配置类生效) spring底层 @Conditional注解,
      //根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效
      @ConditionalOnClass({CharacterEncodingFilter.class}) 
      //判断当前项目有没有这个类;(CharacterEncodingFilter:springmvc中进行乱码解决的过滤器)
      @ConditionalOnProperty(
          prefix = "spring.http.encoding",
          value = {"enabled"},
          matchIfMissing = true
      )  //判断配置文件中是否存在某个配置 spring.http.encoding.enabled,如果不存在,判断也是成立的
         //这句话意思:即使我们配置文件中不配置 pring.http.encoding.enabled=true,也是默认生效的
      public class HttpEncodingAutoConfiguration {
          private final HttpEncodingProperties properties;//他已经和 spring boot的配置文件映射了
         
          //只有一个有参构造器的情况下,参数的值就会从容器中拿
          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;
          }
      
          @Bean
          public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
              return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
          }
      
          private static class LocaleCharsetMappingsCustomizer implements EmbeddedServletContainerCustomizer, Ordered {
              private final HttpEncodingProperties properties;
      
              LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {
                  this.properties = properties;
              }
      
              public void customize(ConfigurableEmbeddedServletContainer container) {
                  if (this.properties.getMapping() != null) {
                      container.setLocaleCharsetMappings(this.properties.getMapping());
                  }
      
              }
      
              public int getOrder() {
                  return 0;
              }
          }
      }
      

      HttpEncodingAutoConfiguration,根据当前不同的条件判断,决定这个配置类是否生效?

      一旦这个配置类生效;这个配置类,就会给容器添加各种组件;这些组件的属性是从对应的 properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的.

    5. 所有在配置文件中能配置的属性都在 xxxProperties类中封装这,配置文件能配置什么就可以参照某个功能对应的这个属性类

    • 精髓:
      1. spring boot启动回家再大量的自动配置类
      2. 我们看我们需要的功能有没有 spring boot默认写好的自动配置类
      3. 我们再来看这个自动配置类中到底配置了那些组件(只要我们用的组件有,我们就不需要再来配置了)
      4. 给容器中自动配置类添加组建的时候,会从 properties类中获取某些属性.我们就可以在配置文件中指定这些属性的值
        xxxAutoConfiguration:自动配置类;
        给容器中添加组件
        xxxProperties:封装配置文件中相关属性;

    8.2 细节 @Conditional

    1. @Conditional 派生注解(spring注解原生的 @Conditional)
      作用:必须是 @Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效.

      @Conditional扩展注解 作用(判断是否满足当前指定条件)
      @ConditionalOnJava 系统的java版本是否符合要求
      @ConditionalOnBean 容器中存在指定Bean;
      @ConditionalOnMissingBean 容器中不存在指定Bean;
      @ConditionalOnExpression 满足SpEL表达式指定
      @ConditionalOnClass 系统中有指定的类
      @ConditionalOnMissingClass 系统中没有指定的类
      @ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
      @ConditionalOnProperty 系统中指定的属性是否有指定的值
      @ConditionalOnResource 类路径下是否存在指定资源文件
      @ConditionalOnWebApplication 当前是web环境
      @ConditionalOnNotWebApplication 当前不是web环境
      @ConditionalOnJndi JNDI存在指定项
      自动配置类必须在一定的条件下才能生效
    • 我们怎么知道那些自动配置类生效?

      我们可以通过启动 debut=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道那些自动配置类生效;

      =========================
      AUTO-CONFIGURATION REPORT 
      =========================
      
      
      Positive matches://自动配置类启用的
      -----------------
      
         DispatcherServletAutoConfiguration matched:
            - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
            - @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
      
      Negative matches: //没有自动,没有匹配成功的自动配置类
      -----------------
      
         ActiveMQAutoConfiguration:
            Did not match:
               - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
      
      
  • 相关阅读:
    kvm系列之二:kvm日常管理
    kvm系列之一:构建kvm虚拟机(centos7)
    cobbler无人值守安装
    判断我们的服务器是物理机还是虚拟机
    kickstark无人值守安装
    找回密码之单用户模式
    rsync传输引起的网络延迟
    题解 P3628 【[APIO2010]特别行动队】
    题解 P3211 【[HNOI2011]XOR和路径】
    题解 POJ1094 【Sorting It All Out】
  • 原文地址:https://www.cnblogs.com/zk2020/p/15338325.html
Copyright © 2011-2022 走看看