SpringBoot之配置

Posted milkywaygalaxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot之配置相关的知识,希望对你有一定的参考价值。

 回顾:

SpringBoot之基础

配置文件

① 两种全局配置文件(文件名是固定的)

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

    application.properties(优先级高)

    application.yml / application.yaml

    配置文件的作用: 修改SpringBoot自动配置的默认值

② YAML

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

    实例: 

技术分享图片技术分享图片?

    YAML的基本语法

        - 使用缩进表示层级关系

        - 缩进时不允许使用tab键, 只允许使用空格

        - 缩进的空格数目不受限制, 只要相同层级的元素在左侧对齐即可

        - 大小写敏感

    YAML支持的三种数据结构

        - 对象 / Map(属性和值): 键值对的集合

            普通写法:

            friends: 

                lastName: zhangsan

                age: 20

            行内写法: 

            friends: {lastName: zhangsan,age: 20}

        - 数组: 一组按次序排列的值

            用- 值表示数组中的一个元素

                普通写法:

                pets:

                    - cat

                    - pig

                    - dog

                行内写法: 

                pets: [cat,pig,dog]

        - 字面量(普通的值, 如: 数字 字符串 布尔): 单个的 / 不可再分的值

            直接写: 字符串默认不用加单引号或双引号

                "": 双引号不会转义字符串里面的特殊字符, 特殊字符作为其本身的意义输出

                    如: name: ‘zhangsan  lisi‘   ==>  代表为  zhangsan 换行 lisi

                ‘‘:  单引号转义字符串里面的特殊字符, 特殊字符不会作为其本身的意义输出(特殊字符最终只是一个普通的字符串)

                    如: name: ‘zhangsan  lisi‘   ==>  代表为  zhangsan  lisi

③ 实例测试

实体类:

Person:

private String name;
private Integer age;
private Boolean boss;
private Date birth;

private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
技术分享图片

Dog:

private String name;
private Integer age;
技术分享图片

配置文件(application.yml):

技术分享图片技术分享图片?

将配置文件中的每个值映射到属性中:

在Person类上加入以下两个注解:

@Component   //将该组件初始化到容器中, 才能使用@ConfigurationProperties注解的功能
@ConfigurationProperties(prefix = "person")  //该注解指定配置文件(全局配置文件application.yml / application.properties)中具体哪个变量下的值进行一一映射
技术分享图片

技术分享图片技术分享图片?

注: 可以先导入配置文件处理器, 这样在编写配置文件时会有相应的提示

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

  技术分享图片

测试:

@Autowired
Person person;

@Test
public void contextLoads() {
    System.out.println(person);
}

  技术分享图片

测试结果:

技术分享图片技术分享图片?

 配置文件(application.properties):

技术分享图片技术分享图片?

测试结果:

技术分享图片技术分享图片?

 另一种获取配置文件的值的方式(@Value("字面量 / ${key} / #{SpEL表达式}")):

技术分享图片技术分享图片?

测试结果:

技术分享图片技术分享图片?

@ConfigurationProperties和@Value的区别:

  @ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法) 支持(如: first-name和firstName相同) 不支持(只支持first-name)
SpEL表达式 不支持 支持(如: #{2.3*10})
JSR303数据校验(在类上使用@Validated注解)

支持(如: 在某个字段上使用@Email注解,

则该字段必须为邮箱格式才正确, 否则报错)

不支持
复杂类型封装 支持(如: 取Map或List或对象中的值) 不支持

数据校验格式:

技术分享图片技术分享图片?

技术分享图片技术分享图片?

小结: 

如果只是在某个业务逻辑中需要获取一下配置文件中的某项或某几项值, 则使用@Value注解; 如果专门编写了一个javaBean来和配置文件进行映射, 此时则需要@ConfigurationProperties注解.

技术分享图片技术分享图片?

技术分享图片技术分享图片?

从非全局配置文件中获取值进行映射的注解:

1) @  PropertySource(value={"配置文件的路径",...})

技术分享图片技术分享图片?

将之前的属性值都移到person.properties文件中, 测试能否将值注入Person类下的属性内.

 

2) @ImportResource: 导入Spring的配置的文件, 让配置文件的内容生效

技术分享图片技术分享图片?

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.idea.springbott.service.HelloService"></bean>
</beans>

  

HelloService:

@Autowired
ApplicationContext ac;

@Test
public void testHelloService(){
    boolean b = ac.containsBean("helloService");
    System.out.println(b);
}

  技术分享图片

SpringBoot推荐给容器中添加组件的方式: 全注解方式

① 配置类<====>配置文件

② @Bean注解: 类同于配置文件中的<bean></bean>标签, 意为将方法的返回值添加到容器中

MyConfig配置类:

@Configuration
public class MyAppConfig {

    @Bean
    public HelloService helloService(){
        System.out.println("配置类给容器添加组件了...");
        return new HelloService();
    }
}
技术分享图片

配置文件占位符:

① 随机数

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

② 占位符获取之前的属性值, 如果没有则可以指定默认值

属性配置:

person.name=王五${random.uuid}
person.age=${random.int}
person.boss=true
person.birth=2018/12/07
person.maps.k1=v1
person.maps.k2=15
person.lists=a,b,c
person.dog.name=${person.name:此处填写默认值}的dog
person.dog.age=18
技术分享图片

技术分享图片技术分享图片?

 

profile标识: 动态切换, 以便适应不同的环境(开发环境 / 测试环境 / 生产环境等)

激活方式

1) spring.profiles.active=[具体的profile的名称]

2) 命令行: 打包成jar, 利用控制台方式启动(java -jar [部署包的名称] --spring.profiles.active=[profile的名称])

    或者在idea中的Edit Configurations中进行设置也是属于命令行的一种方式

3) 虚拟机参数(VM options): -Dspring.profiles.active=[profile的名称]

① .properties文件的切换方式

        在主配置文件编写的时候, 文件名可以是 application-[profile标识].properties/yml

        如: application-dev.properties(表示开发环境) / application-prod.properties(表示生产环境)

        默认情况下使用application.properties / application.yml主配置文件, 如果需要切换环境配置文件, 需要在主配置文件里面激活该需要切换的配置文件, 如: spring.profiles.active=[profile标识]

spring.profiles.active=dev
技术分享图片

② .yml文件的切换方式(文档块)

        技术分享图片技术分享图片?

内部配置文件的加载顺序:

4个存放位置: 按照优先级从高到低排列, 高优先级的配置覆盖低优先级的配置

① file: /config/   ==> 当前项目下的config文件夹下  优先级最高

② file: /   ==> 当前项目下  优先级第二

③ classpath: /config/   ==> classpath下的config文件夹下  优先级第三

④ classpath: /   ==> classpath下  优先级第四

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

通过spring.config.location来改变默认的配置文件的位置

① 打包项目

② 使用命令行参数的形式, 在启动项目的时候指定配置文件的新位置, 指定的配置文件会和默认加载的配置文件共同起作用形成互补配置

外部配置文件的加载顺序:

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

① 命令行参数

    java -jar [jar包名] --server.port=8089 / 其他命令也行(多个参数用空格隔开).

优先加载带spring.profiles.active, 并且由外部向内部加载(外部的优先级比内部的高)

② jar包外部的application-[profile的名称].properties / .yml(带spring.profiles.active)配置文件

③ jar包内部的application-[profile的名称].properties / .yml(带spring.profiles.active)配置文件

再加载不带spring.profile, 并且由外部向内部加载(外部的优先级比内部的高)

④ jar包外部application-[profile的名称].properties / .yml(不带spring.profiles.active)配置文件

⑤ jar包内部application-[profile的名称].properties / .yml(不带spring.profiles.active)配置文件

技术分享图片技术分享图片?

⑥ @Configuration注解类上的@PropertySource指定配置文件

自动配置原理:

配置文件能配置的属性

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

2) @EnableAutoConfiguration的作用:

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

    selectImports(AnnotationMetadata annotationMetadata) ==> List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);  //获取候选项的配置

    ① SpringFactoriesLoader.loadFactoryNames()

    ② classLoader.getResources("META-INF/spring.factories")  //扫描所有jar包类路径下的META-INF/spring.factories

         把扫描到的内容封装成properties对象, 并从中取出EnableAutoConfiguration.class类对应的值, 最后把它们添加进容器中.

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

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

4) 所有在配置文件中能配置的属性都是在xxxProperties类中封装着

    HttpEncodingProperties: 该类上标注了@ConfigurationProperties(prefix = "spring.http.encoding")注解

                                            该注解从配置文件中获取指定的值和bean的属性进行绑定

5) 举例: HttpEncodingAutoConfiguration(http编码的自动配置)

    @Configuration    //这是一个配置类
    @EnableConfigurationProperties({HttpEncodingProperties.class})    //启动指定类的ConfigurationProperties的功能; 将配置文件中对应的值和HttpEncodingProperties绑定起来;
    @ConditionalOnWebApplication  //Spring底层有@Conditional注解, 根据不同的条件, 如果满足指定的条件, 整个配置类才会生效.(判断当前应用是否是web应用, 如果是: 当前配置类生效)
    @ConditionalOnClass({CharacterEncodingFilter.class})  //判断当前项目是否有CharacterEncodingFilter类

        CharacterEncodingFilter: 是SpringMVC中进行乱码解决的过滤器
    @ConditionalOnProperty(prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true)  //判断配置文件中是否存
        在某个配置, 即: spring.http.encoding.enabled; matchIfMissing = true: 如果文件不存在, 判断也是成立的(也就是说, 即使不配

        置spring.http.encoding.enabled=true, 也是默认生效的)

private final HttpEncodingProperties properties;  //该属性已经和SpringBoot的配置文件进行映射了

//只有一个有参构造器的情况下, 参数的值就会从容器中拿
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;
}

 

所以, HttpEncodingAutoConfiguration这个类的意义就是根据当前不同的条件进行判断, 决定这个配置类是否生效.

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

总结: 

① SpringBoot启动会加载大量的自动配置类

② 查看需要的功能有没有SpringBoot默认写好的自动配置类

③ 如果有, 这个配置类配置了哪些组件(需要则注入即可, 无需再配置), 如果没有, 则需要自己写配置类

④ 给容器中的自动配置类添加组件的时候, 会从properties类中获取某些属性, 就可以在配置文件中指定这些属性的值(跟配置文件绑定了)

 

附:

由于自动配置类必须在一定条件下才能生效, 所以可以通过在配置文件中启用debug=true属性, 让控制台打印自动配置报告, 即能很方便知道具体哪些配置类生效哪些配置类不生效.







以上是关于SpringBoot之配置的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot中级教程之SpringBoot自定义配置

SpringBoot中级教程之SpringBoot自定义配置

springboot+rabbitmq 之 消费端配置

SpringBoot之常用注解

SpringBoot之常用注解

附 5 springboot之配置文件