• Spring Boot配置文件


    一、基本介绍

      Spring Boot提供了两种常用的配置文件,分别是properties文件和yml文件。

    • application.properties
    • application.yml

      他们的作用都是修改Spring Boot自动配置的默认值。相对于properties文件而言,yml文件更年轻,也有很多的坑。可谓成也萧何败也萧何,yml通过空格来确定层级关系,使配置文件结构更清晰,但也会因为微不足道的空格而破坏了层级关系。

    二、YAML简介

    yml是YAML(YAML Ain't Markup Language)语言的文件,以数据为中心,比json、xml等更适合做配置文件

      以前的配置文件;大多都使用的是 xxxx.xml文件;yml和xml相比,少了一些结构化的代码,使数据更直接,一目了然。举例:

      YAML

    server:
      port: 8081
    

      XML:

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

      yml和json呢?没有谁好谁坏,合适才是最好的。yml的语法比json优雅,注释更标准,适合做配置文件。json作为一种机器交换格式比yml强,更适合做api调用的数据交换。

    2.1 YAML的语法

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

      以空格的缩进程度来控制层级关系。空格的个数并不重要,只要左边空格对齐则视为同一个层级。注意不能用tab代替空格。且大小写敏感。

    server:
        port: 8081
        path: /hello
    

      YAML支持字面值,对象,数组三种数据结构,也支持复合结构。

    【字面值】——字符串,布尔类型,数值,日期。

      k: v:字面直接来写;

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

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

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

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

    name:   ‘zhangsan 
     lisi’:输出;zhangsan 
      lisi
    

    【对象】

      由键值对组成,形如 key:(空格)value 的数据组成。冒号后面的空格是必须要有的,每组键值对占用一行,且缩进的程度要一致。

    friends:
            lastName: zhangsan
            age: 20
    

      也可以使用行内写法:{k1: v1, ....kn: vn}

    friends: {lastName: zhangsan,age: 18}
    

    【数组】——List、Set

      由形如 -(空格)value 的数据组成。短横线后面的空格是必须要有的,每组数据占用一行,且缩进的程度要一致,也可以使用行内写法: [1,2,...n]

    pets:
     - cat
     - dog
     - pig
    

      行内写法

    pets: [cat,dog,pig]
    

    2.2 YAML的运用

      创建一个Spring Boot 的全局配置文件 application.yml,配置属性参数。

    person:
      lastName: hello
      age: 18
      boss: false
      birth: 2019/7/14
      maps: {k1: v1,k2: v2}
      lists:
        - zhangsan
        - lisi
      dog:
        name: 小狗
        age: 12
    

      创建实体类Person.java 获取配置文件中的属性值,通过注解@ConfigurationProperties获取配置文件中的指定值并注入到实体类中。

    /**
     * 将配置文件中配置的每一个属性的值,映射到这个组件中
     * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
     *      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> maps;
        private List<Object> lists;
        private Dog dog;
    
        // 省略getter,setter,toString方法  
    }
    

      我们可以导入配置文件处理器,以后编写配置就有提示了

    <!--导入配置文件处理器,配置文件进行绑定就会有提示-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    

      创建一个单元测试类:

    /**
     * SpringBoot单元测试;
     *
     * 可以在测试期间很方便的类似编码一样进行自动注入等容器的功能
     *
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class PersonTest {
        @Autowired
        private Person person;
    
        @Test
        public void test() {
            System.out.println(person);
        }
    }
    

    img

      注意:在运行测试类之前,要确保spring boot的引导类(主程序)是已启动状态。

    2.3 YML小结

    1. 字符串可以不加引号,若加双引号则输出特殊字符,若不加或加单引号则转义特殊字符;
    2. 数组类型,短横线后面要有空格;对象类型,冒号后面要有空格;
    3. YAML是以空格缩进的程度来控制层级关系,但不能用tab键代替空格,大小写敏感;
    4. 如何让一个程序员崩溃?在yml文件中加几个空格!

    三、Properties简介

      properties文件经常用,这里就简单介绍一下。其语法结构形如:key=value。

    userinfo.account=zhangsan
    userinfo.age=25
    userinfo.active=true
    userinfo.created-date=2019/07/14 16:54:30
    userinfo.map.k1=v1
    userinfo.map.k2=v2
    userinfo.list=one,two,three
    

      从配置文件中取值注入到实体类中,和YAML是一样的。

    /**
     * 用户信息
     * @ConfigurationProperties : 被修饰类中的所有属性会和配置文件中的指定值(该值通过prefix找到)进行绑定
     */
    @Component
    @ConfigurationProperties(prefix = "userinfo")
    public class UserInfo {
    
        private String account;
        private Integer age;
        private Boolean active;
        private Date createdDate;
        private Map<String, Object> map;
        private List<Object> list;
    
       // 省略getter,setter,toString方法
    }
    

       注意:properties配置文件在idea中默认utf-8可能会乱码。调整如下:

    img

      【注意】:spring boot项目中同时存在application.properties和application.yml文件时,两个文件都有效,但是application.properties的优先级会比application.yml高。

    四、配置文件取值

      Spring Boot通过ConfigurationProperties注解从配置文件中获取属性。从上面的例子可以看出ConfigurationProperties注解可以通过设置prefix指定需要批量导入的数据。支持获取字面值,集合,Map,对象等复杂数据。ConfigurationProperties注解还有其他特么呢?它和Spring的Value注解又有什么区别呢?带着这些问题,我们继续往下看。

    4.1 ConfigurationProperties和Value对比

    img

      ConfigurationProperties注解的优缺点

    1. 可以从配置文件中批量注入属性;
    2. 支持获取复杂的数据类型;
    3. 对属性名匹配的要求较低,比如user-name,user_name,userName,USER_NAME都可以取值;
    4. 支持JAVA的JSR303数据校验;
    5. 缺点是不支持强大的SpEL表达式;

      Value注解的优缺点正好相反,它只能一个个配置注入值;不支持数组、集合等复杂的数据类型;不支持数据校验;对属性名匹配有严格的要求。最大的特点是支持SpEL表达式,使其拥有更丰富的功能。  

    4.2 @ConfigurationProperties详解

      第一步:导入依赖。若要使用ConfigurationProperties注解,需要导入依赖 spring-boot-configuration-processor;

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    

       第二步:配置数据。在application.yml配置文件中,配置属性参数,其前缀为employee,参数有字面值和数组,用来判断是否支持获取复杂属性的能力;(nick-name是用来判断匹配属性的松散性,若换成nick_name依然可以获取值。)

    employee:
      nick-name: itachi
      email: 123456@126.com
      phone: 1234567
      abilities: [java,sql,html]
      created_date: 2019/7/14 13:40
    

      第三步:匹配数据。在类上添加注解ConfigurationProperties,并设置prefix属性值为employee。并把该类添加到Spring的IOC容器中。

      第四步:校验数据。添加数据校验Validated注解,开启数据校验,测试其是否支持数据校验的功能;

      第五步:测试ConfigurationProperties注解是否支持SpEL表达式;

    /**
     * ConfigurationProperties 注解语法类
     * 第一步:导入依赖 spring-boot-configuration-processor;
     * 第二步:把ConfigurationProperties注解修饰的类添加到Spring的IOC容器中;
     * 第三步:设置prefix属性,指定需要注入属性的前缀;
     * 第四步:添加数据校验注解,开启数据校验;
     *
     * 注意点:
     * 一、nickName和createdDate在yml配置文件中,对应参数分别是中划线和下划线,用于测试其对属性名匹配的松散性
     * 二、email和iphone 测试其支持JSR303数据校验
     * 三、abilities 测试其支持复杂的数据结构
     */
    @Component
    @ConfigurationProperties(prefix = "employee")
    @Validated
    public class ConfigurationPropertiesEntity {
        private String nickName; // 解析成功,支持松散匹配属性
        private String email;
        // @Email //表示phone必须填成email格式。此处解析失败:Binding validation errors on employee
        private String phone;
        private List<String> abilities;
        private Date createdDate; // 解析成功,支持松散匹配属性
    
        // @ConfigurationProperties("#{11*2}") //语法报错,不支持SpEL表达式:not applicable to field
        private String operator;
    
       // 省略get/set和toString方法  
    }
    

    4.3 @Value详解

      第一步:在属性上添加Value注解,通过${}设置参数从配置文件中注入值;

      第二步:修改${employee.ceatred_date}中的参数值,改为${employee.ceatredDate}测试是否能解析成功;

      第三步:添加数据校验Validated注解,开启数据校验,测试其是否支持数据校验的功能;

      第四步:测试Value注解是否支持SpEL表达式;

    /**
     * Value 注解语法类
     * 第一步:在属性上添加注解Value注入参数
     * 第二步:把Value注解修饰的类添加到Spring的IOC容器中;
     * 第三步:添加数据校验注解,检查是否支持数据校验;
     *
     * 注意点:
     * 一、nickName和createdDate在yml配置文件中,对应参数分别是中划线和下划线,用于测试其对属性名匹配的松散性
     * 二、email和iphone 测试其支持JSR303数据校验
     * 三、abilities 测试其支持复杂的数据结构
     *
     * 结论:
     * 一、createDate取值必须和yml配置文件中的参数保持一致,
     * 二、既是在iphone上添加邮箱验证注解依然可以通过测试,
     * 三、不支持复杂的数据结构,提示错误和第一条相同:IllegalArgumentException: Could not resolve placeholder 'itdragon.abilities' in value "${itdragon.abilities}"
     */
    @Component
    @Validated
    public class ValueEntity {
        @Value("${employee.nick-name}")
        private String nickName;
        @Value("${employee.email}")
        private String email;
        @Email
        @Value("${employee.phone}") // 解析成功,并不支持数据校验
        private String phone;
        // @Value("${employee.abilities}") //解析错误,并不支持复杂的数据结构
        private List<String> abilities;
        // @Value("${employee.createDate}") // 解析错误,并不支持松散匹配属性,必须严格一致
        @Value("${employee.created_date}")
        private Date createDate;
    
        // Value注解的强大一面:支持SpEL表达式
        @Value("#{11*2}") // 算术运算
        private String operator;
    
        @Value("#{1>2 || 2<=3}") // 关系运算
        private Boolean comparison;
    
        @Value("#{systemProperties['java.version']}") //系统配置:os.name
        private String systemProperties;
    
        @Value("#{T(java.lang.Math).abs(-18)}") // 表达式
        private String mapExpression;
       
        // 省略get/set和toString()
    }    
    

    4.4 配置文件取值小结

    1. ConfigurationProperties注解支持批量注入,而Value注解适合单个注入;
    2. ConfigurationProperties注解支持数据校验,而Value注解不支持;
    3. ConfigurationProperties注解支持松散匹配属性,而Value注解必须严格匹配属性;
    4. ConfigurationProperties不支持强大的SpEL表达式,而Value支持;

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

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

    五、@PropertySource&@ImportResource&@Bean

    5.1 @PropertySource

      @ConfigurationProperties注解默认只能读取系统全局的配置文件,要加载非全局的配置,需要使用@PropertySource加载文件。@PropertySource的目的是加载指定的属性文件。

      比如定义一个person.properties

    person.last-name=李四
    person.age=12
    person.birth=2019/7/14
    person.boss=false
    person.maps.k1=v1
    person.maps.k2=14
    person.lists=a,b,c
    person.dog.name=dog
    person.dog.age=15
    

      如果要在配置类中加载person.properties配置文件,则需要用到@PropertySource

    /**
     * 将配置文件中配置的每一个属性的值,映射到这个组件中
     * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
     *      prefix = "person":配置文件中哪个下面的所有属性进行一一映射
     *
     * 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;
     *  @ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值;
     *
     */
    @PropertySource(value = {"classpath:person.properties"})
    @Component
    @ConfigurationProperties(prefix = "person")
    public class Person {
        private String lastName;
        private Integer age;
        private Boolean boss;
        private Date birth;
    
        private Map<String, Object> maps;
        private List<Object> lists;
        private Dog dog;
    
        // 省略get/set和toString()方法
    }
    

    5.2 @ImportResource

      编写一个HelloService.java

    public class HelloService {
    }
    

      编写一个beans.xml

    <?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.pinyougou.service.HelloService"></bean>
    </beans>
    

      在测试类中测试该配置文件有没有生效:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringBootConfigApplicationTest {
    
        @Autowired
        private ApplicationContext context;
    
        @Test
        public void testHelloService() {
            boolean b = context.containsBean("helloService");
            System.out.println(b); // false
        }
    }
    

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

      想让Spring的配置文件生效,加载进来;可以使用@ImportResource标注在一个配置类上:

    @ImportResource(locations = {"classpath:beans.xml"})
    @SpringBootApplication
    public class SpringbootdemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootdemoApplication.class, args);
        }
    }
    

      这时候再次运行testHelloService()测试方法,结果为true。说明自己编写的beans.xml配置文件已经生效了。

      总结:@ImportResource的作用是:导入Spring的配置文件,让配置文件里面的内容生效;

    5.3 @Bean

      虽然使用@ImportResource能导入我们编写的配置文件,但是SpringBoot并不推荐这种方式,SpringBoot推荐使用全注解的方式来给容器中添加组件。这时候就使用到了@Bean来给容器中添加组件。

      为了测试效果明显,将beans.xml删掉,并且将@ImportResource注释掉:

    img

      创建一个配置类:

    /**
     * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件。@Configuration可理解为用spring的时候xml里面的<beans>标签。
     * @Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文对象) 
     */
    @Configuration
    public class MyAppConfig {
    
        // 将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名   // @Bean标注在方法上(返回某个实例的方法),等价于spring配置文件中的<bean></bean>,作用为:注册bean对象
        // @Bean可理解为用spring的时候xml里面的<bean>标签。  
        @Bean
        public HelloService helloService() {
            System.out.println("配置了@Bean给容器中添加了组件。。。");
            return new HelloService();
        }
    }
    

      再次运行测试类:

      img

      注意:

    1. @Bean注解在返回实例的方法上,如果未通过@Bean指定bean的名称,则默认与标注的方法名相同;
    2. @Bean注解默认作用域为单例singleton作用域,可通过@Scope(“prototype”)设置为原型作用域;
    3. 既然@Bean的作用是注册bean对象,那么完全可以使用@Component、@Controller、@Service、@Repository等注解注册bean(在需要注册的类上加注解),当然需要配置@ComponentScan注解进行自动扫描。

      Spring Boot不是spring的加强版,所以@Configuration和@Bean同样可以用在普通的spring项目中。

    六、配置文件占位符

      占位符和随机数比较简单,这里就直接贴出代码。需要注意的是:

    • 占位符的值必须是完整路径
    • 占位符设置默认值,冒号后面不能有空格
    ran:  # 这里的prefix不能是random,
      ran-value: ${random.value}
      ran-int: ${random.int}
      ran-long: ${random.long}
      ran-int-num: ${random.int(10)}
      ran-int-range: ${random.int[10,20]}
      ran-placeholder: placeholder_${ran.ran-value:此处不能有空格,且key为完整路径} 
    /**
     * 随机数和占位符语法类
     */
    @Component
    @ConfigurationProperties(prefix = "ran")
    public class RandomEntity {
    
        private String ranValue;    // 随机生成一个字符串
        private Integer ranInt;     // 随机生成一个整数
        private Long ranLong;       // 随机生成一个长整数
        private Integer ranIntNum;  // 在指定范围内随机生成一个整数
        private Integer ranIntRange;// 在指定区间内随机生成一个整数
        private String ranPlaceholder;// 占位符
    
        // 省略getter,setter,toString方法e
    }
    

      测试代码:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringBootYmlApplicationTests {
        @Autowired
        private RandomEntity randomEntity;
    
        @Test
        public void contextLoads() {
            System.out.println("Random Grammar : " + randomEntity);
        }
    
    }
    

    七、Profile多环境支持

    7.1 使用properties作为配置文件时

      我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties。如:

      application-dev.properties

      img

      application-prod.properties

      img

      application.properties主配置文件

      img

      运行主程序时,默认使用的是application.properties主配置文件的端口号:8080

      当我们要激活指定的profile时,比如要激活开发环境的8081端口,可以在主配置文件中添加spring.profiles.active=dev

      img

    7.2 使用yml作为配置文件时

      yml支持多文档块方式

    server:
      port: 8080
    spring:
      profiles:
        active: prod #指定使用生产环境运行
    ---
    server:
      port: 8081
    spring:
      profiles: dev
    ---
    server:
      port: 8082
    spring:
      profiles: prod
    

    7.3 激活指定的profile

      除了在配置文件中通过代码来激活指定的profile,还可以通过命令行和指定虚拟机参数的方式来激活指定的profile。

    【命令行】

      可以直接在测试的时候,配置传入命令行参数:

      img

      此外,如果将项目package后,也可以通过命令行的方式来指定profile:

      img

    【虚拟机参数】

    img

    八、配置文件的加载路径及顺序

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

    1. 工程根目录的config目录:file:./config/
    2. 工程根目录:file:./
    3. 类路径的config目录:classpath:/config/
    4. 类路径:classpath:/

      如果存在多个配置文件,则严格按照优先级进行覆盖,最高者胜出。如下图1~4优先级从高到低:

       img

      SpringBoot会从这四个位置全部加载主配置文件;互补配置

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

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

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

    参考:https://www.cnblogs.com/itdragon/p/8686554.html

  • 相关阅读:
    2019春第八周作业
    2019春第七周作业
    第六周作业
    币值转换
    打印沙漏
    秋季学期学习总结
    人生影响最大的三位老师
    自我介绍
    2018秋季学习总结
    自己
  • 原文地址:https://www.cnblogs.com/yft-javaNotes/p/11183533.html
Copyright © 2020-2023  润新知