Spring Boot配置相关

SpringBoot配置文件

Spring Boot使用的配置文件的名字是固定的都是application,配置文件的类型可以是properties也可以是yml

  • application.properties
  • application.yml / application.yaml

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

YAML(YAML Ain't Markup Language)

概述

以前的配置文件大多是xml文件,配置起来显得很冗长,很多。而yaml以数据为中心,比json、xml等更适合做配置文件

创建

yml文件写在跟application.properties文件同级的目录下,可以是application.yml,也可以是application.yaml

下面介绍yaml的写法,以修改端口为例,yaml的写法为

server:
  port: 8081

YAML语法

基本语法

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

  • 以空格的缩进来控制层级关系,只要是左对齐的数据都是属于同一层级的

  • 属性跟值的大小写敏感
server:
  port: 8081
  path: /hello

值的写法

不管是在yaml还是在properties里面,值都有以下三种

字面量

字面量即普通的值,包括数字,字符串和布尔值等

写法:

k: v: 字面量

yaml中字符串不需要加上引号,如果加上了引号,对于不同的引号也有不同的作用

  • "":双引号表示不会转义字符里面的特殊字符
  • '':单引号表示会转义字符串里面的特殊字符,特殊字符最终只是一个普通的字符串
对象、Map

对象跟Map的值是属性跟值或者键值对

写法:

friends:
    lastName: zhangsan
    age: 20

除了上面的写法,其实还有一种写法,叫做行内写法

行内写法:

friends: {lastName: zhangsan, age: 20}
数组、List、Set

数组等用 -值 的形式代表数组中的一个值

写法:

pets:
    -cat
    -dog
    -pig

它也有行内写法

行内写法:

pets: [cat, dog, pig]

配置文件注入

在配置文件中写好值后就需要注入了,对于Spring Boot配置的默认值修改当然不需要注入,只管修改,Spring Boot已经做好了注入,但是对于我们自己写的类里面的属性还是有必要做注入的,那么注入的方式有哪些呢?这里列举两种,分别是使用 @ConfigurationProperties 注解跟 @Value 注解注入配置文件中的值,当然,无论使用哪一种方式注入,都需要先使用 @Component 注解把类加载到容器中才能生效,下面介绍两种注入方式

注入方式一:@ConfigurationProperties

配置文件

配置文件可以选取yml文件,也可以选取properties文件,下面对两种文件都做介绍

使用yml写:

person:
  lastName: hello
  age: 18
  boss: false
  birth: 2017/12/12
  maps: {k1: v1, k2: v2}
  lists:
      - lisi
      - zahngsan
  dog:
    name: 小狗
    age: 2
YAML

使用properties写:

person.last-name=张三
person.age=18
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=v2
person.lists=a, b, c
person.dog.name=小狗
person.dog.age=2
Properties

值得注意的是由于properties默认是ascii编码,而IDEAutf8编码,所以还需要对IDEA进行设置才能输出中文

JavaBean

下面写一个javaBean类来作为被注入的对象

/**
 * 将配置文件中配置的每一个属性的值,映射到这个组件中
 * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
 * prefix = "person":配置文件中与哪个键下面的所有属性进行一一映射
 */
@Component     // 只有这个组件是容器中的组件,才能使用容器提供的@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;

}
JavaBean

经过上面的步骤,此时new一个Person对象,其中的属性就会被设置上我们上面在默认文件中设置的值了

但是,我们在配置文件中为属性写默认值的时候发现没有代码提示,这个体验并不是很好,那么怎样开启提示呢?

其实只需要在pom.xml中配置导入配置文件处理器,以后编写配置的时候会有提示了

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

注入方式二:@Value

配置文件还是一样的写法,只是在使用注解的时候发生了改变,当然前提是要写上@Component注解

使用@Value为每个值进行单独赋值,相当于spring配置文件中的bean元素赋值

/**
 * spring中
 * <bean name="person" class="Person">
 *      <property name="lastName" value="字面量/${从环境变量、配置文件中获取值}/#{SpEl}"></property>
 * </bean>
 */
@Value("${person.last-name}")
private String lastName;
@Value("#{11 * 2}")
private Integer age;
@Value("true")
private Boolean boss;

@ConfigurationProperties@Value的比较

 

@ConfigurationProperties

@Value

功能

批量注入配置文件中的属性

一个一个指定值

松散绑定(即松散语法,例如:lastNamelast-name等价)

支持

不支持

SpEL语法

不支持

支持

JSR303数据校验

支持

不支持

复杂类型封装

 

支持

 

不支持

 

 

 

 

 

 

 

 

 

 

 

 

说明

松散绑定

什么是松散绑定?例如在javaBean中有一个属性是 public String lastName; ,而此时在配置文件中写上 last-name 也是可以跟该属性绑定上的,这个就叫做松散语法

JSR303数据校验

JSR303数据校验只有在使用@ConfigurationProperties时才会有效,使用方法是首先在类上面加上@Validated注解,然后在要验证的字段上面加上特定的验证注解

例如:

@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
    @Email   // 规定lastName只能按照邮箱格式填写,否则报错
    private String lastName;
复杂类型

什么是复杂类型?如对象、Map、数组就是复杂类型,像这样的复杂类型使用@Value是没办法注入的,只能使用@ConfigurationProperties

什么时候使用@Value、什么时候使用@ConfigurationProperties?

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

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

@PropertySource & @ImportResource

@PropertySource

这个注解是加载指定的配置文件

有时候,我们不想把person写到application.properties中,就像单独的写一个配置文件用来存放给Person的值,那么在使用@ConfigurationPropertits或者@Value的时候如何去找到这个配置文件呢?这个时候就需要使用@PropertySource来导入这个配置文件了

例:

@Component   
@ConfigurationProperties(prefix = "person")
@PropertySource(value = {"classpath:person.properties"})   // 导入配置文件
public class Person {

注意: @PropertySourcevalue接收的是一个数组,也就是说可以同时加载多个配置文件

@ImportResource

这个注解的作用是导入Spring的配置文件,让配置文件里面的内容生效

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

想让Spring的配置文件生效,需要将@ImportResource标注在一个配置类上

 @ImportResource(locations = {“classpath:bean.xml”}) 

注意,locations对应的同样是一个数组,可以导入多个配置文件

bean.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 name="hello" class="com.jinxin.springboot.HelloService"></bean>
</beans>
View Code

Spring Boot推荐给容器中添加组件的方式

  • Spring Boot推荐使用全注解的方式添加组件,而且不再使用配置文件,而是将配置文件改成了配置类。只需要在类上加上@Configuration注解即可成为配置类
  • 使用@Bean配置组件

例:

/**
 * @Configuration:声明当前类是一个配置类,是用来替换之前的Spring配置文件的
 * 以前在配置文件中使用<bean></bean>添加组件,在配置类中使用@Bean注解
 */
@Configuration
public class MyConfig {

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

配置文件占位符

propertiesYAML中都支持占位符,写法就是${}

占位符里面可以是两种形式,分别是随机数跟前面出现过的属性

随机数

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

例:

person.last-name=李四${random.uuid}
person.age=${random.int}

前面出现过的属性

占位符里面还可以是前面出现过的属性,还可以使用 :默认值 的方式来指定默认值,如果获取不到属性就会使用默认值

例:

person.last-name=李四${random.uuid}
person.dog.name=小姑${person.hello:defaultValue}
person.dog.age=${person.last-name}

profile多环境支持

profile文件

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

例如现在定义了三个文件:application.properties   application-dev.properties  application-prod.properties

Spring Boot会默认执行application.properties里面的内容

yml支持多文档块的方式

除了使用上面的多个配置文件去切换以外,yml还提供了一个更加简便的方式去切换,就是使用文档块的方式,两个文档块用 --- 去分割,分割好后每个文档块相当于一个文档,可以使用相同的方式去切换

例:

server:
  port: 8081
spring:
  profiles:
    active: prod
---
server:
  port: 8082
spring:
  profiles: dev
---
server:
  port: 8083
spring:
  profiles: prod

激活指定的profile

配置文件中修改

上面提到虽然我们定义了三个配置文件,但是Spring Boot会默认执行application.properties文件,那么怎样去使用其余的两个文件呢?

只需要在application.properties中使用spring.profiles.active=dev 即可启用application-dev.properties文件

命令行方式激活

使用--spring.profiles.active=dev的方式去激活

命令行去激活的方式有两种

A. 如果还在测试阶段,可以在IDEA里面去配置命令行参数

B. 如果应用已经打包,那么可以在启动时去修改

Java -jar springboot-01-hello.jar --spring.profiles.active=dev

C. 虚拟机参数

 -Dspring.profiles.active=dev 

Spring Boot配置文件加载的位置

Spring Boot会扫描以下位置的application.properties或者application.yml/yaml文件作为Spring Boot的默认配置文件

  • File:./config/
  • File:./
  • Classpath:/config/
  • Classpath:/

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

各个文件对应的位置:

这四个地方的文件spring Boot全部都会扫描,也就是说四个地方的文件都会生效,而且会形成一个互补配置,即高优先级的配置文件中不具备低优先级配置文件中的某个配置,那么这个配置也会生效

Spring.config.location改变默认配置文件的位置

项目打包好以后,可以使用命令行参数的形式,在启动项目的时候来指定配置文件的新位置,指定的配置文件会和默认加载的四个位置的文件一起起作用,形成互补配置

 Java -jar springboot-project.jar --spring.config.location=G:/springbot/application.properties 

外部配置加载顺序

SpringBoot除了从项目中的application.properties中加载配置外,还可以从以下位置加载配置(优先级从高到低,高优先级配置会覆盖低优先级配置,所有配置形成互补)

  • 命令行参数

  • 来自java:comp/env的JNDI属性

  • Java系统属性(System.getProperties())

  • 操作系统环境变量

  • RandomValuePropertySource配置的random.*属性值

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

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

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

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

  • @Configuration注解类上的@PropertySource

  • 通过SpringApplication.setDefaultProperties指定的默认属性

这里重点说一下命令行参数加载跟jar包内外配置文件加载

命令行参数

有的时候在配置比较少的情况下如果使用一个配置文件装着觉得太麻烦了,那么这时候可以在启动应用得到时候顺面添加配置

java -jar spring-boot.jar –server.port=8087 –server.context-path=/proj

 多个配置可以用空格间隔

jar包内外配置文件加载

加载jar包内外配置文件的机制:

  • jar包外向jar包内寻找

  • 先加载带profile的,再加载不带profile的

将应用打成jar包以后,启动时会先到jar包外部找配置文件加载,然后在jar包内部找配置文件加载

 

这里只列举了11中加载位置,官方提供了17种,详细可参考官方文档

自动配置原理

配置文件能配置的属性有哪些呢?这个可以参考官方文档

自动配置精髓

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

xxxAutoConfiguration:自动配置类

给容器中添加组件

xxxProperties:封装配置文件中的相关属性

例:

按住CTRL + N搜索*AutoCnfiguration

这里以数据源自动配置类为例

点进去后我们会发现一个DataSourceProperties类,这里面有能够在properties中配置的所有属性

这里面使用@ConfigurationProperties注解引入了spring.datasource前缀,这说明我们在properties文件中配置的时候也应该使用相同的前缀

然后就是这里面能配置的属性了,只要在properties文件中拿前缀就能”点”出来

properties

@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存在指定项

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

因为加上了这些@Conditional,所以自动配置类必须在一定条件下才能生效

那么我们怎么知道那些自动配置类能生效呢?

其实可以在properties或者yml文件中设置debug=true来让控制台打印自动配置报告。这样我们可以很方便的知道那些自动配置类生效了

 

posted @ 2018-09-05 22:02  Jin同学  阅读(192)  评论(0)    收藏  举报