天天看點

SpringBoot學習筆記-2:第二章 Spring Boot 配置第二章 Spring Boot 配置

第二章 Spring Boot 配置

1、YAML 配置

SpringBoot 全局配置檔案

application.properties
application.yml      

YAML 以資料為中心,比 json、xml 更适合作為配置檔案

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

2、YAML 文法

https://yaml.org/

YAML 語言教程:

http://www.ruanyifeng.com/blog/2016/07/yaml.html

1、基本文法

key:空格value      
  1. 空格縮進來控制層級關系,左對齊的資料就是一個層級
  2. 屬性和值大小寫敏感
  3. 空格必須有

2、值的寫法

2.1、字面量:普通的值(數字,字元串,布爾)

字元串預設不用加單引号或者雙引号

(1)""雙引号不會轉義特殊字元。特殊字元會作為本身想表達的意思

eg:

name: "張三\n李四"

輸出:
張三[換行]
李四      

2.2、對象,map(屬性和值,鍵值對)

(1)普通寫法

person:
  name: Tom
  age: 23      

(2)行内寫法

person: { name: Tom, age: 23 }      

2.3、數組,(List, Set)

pets:
  - cat
  - dog
  - pig      
pets: [cat, dog, pig]      

3、YAML 配置檔案中值擷取

配置檔案

src/main/resources/application.yml

person:
  lastName: Tom
  age: 18
  boss: false
  birth: 2017/12/12
  maps: { k1: v1, k2: v2 }
  lists:
    - cat
    - dog
  dog:
    name: Jack
    age: 2      

映射類

src/main/java/com/mouday/bean/Person.java

package com.mouday.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 将配置檔案中的屬性映射到這個元件中
 */
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean sex;
    private Date birth;
    private Map<String, Object> maps;
    private List<String> lists;
    private Dog dog;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getSex() {
        return sex;
    }

    public void setSex(Boolean sex) {
        this.sex = sex;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<String> getLists() {
        return lists;
    }

    public void setLists(List<String> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}      

src/main/java/com/mouday/bean/Dog.java

package com.mouday.bean;

public class Dog {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
      

單元測試依賴

pom.xml

<!--配置檔案處理器 導入配置檔案導入提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
      

單元測試

src/test/java/com/mouday/DemoApplicationTests.java

package com.mouday;

import com.mouday.bean.Person;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private Person person;

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

列印結果

Person{name='Tom', age=18, sex=false, birth=Tue Dec 12 00:00:00 CST 2017,
    maps={k1=v1, k2=v2},
    lists=[cat, dog],
    dog=Dog{name='Jack', age=2}
}      

讀取 properties 檔案配置

src/main/resources/application.properties

person.name=TOM
person.age=18
person.sex=false
person.birth=2017/12/12
person.maps.k1=v1
person.maps.k2=v2
person.lists=cat,dog
person.dog.name=Jack
person.dog.age=2      

4、@ConfigurationProperties 與@Value 差別

@ConfigurationProperties @Value
功能 批量注入配置檔案中的屬性 一個一個指定
松散綁定 支援 不支援
SpEL
JSR303 資料校驗
複雜類型封裝

屬性名比對規則

person.firstName
person.first-name
person.first_name
PERSON_FIRST_NAME      
package com.mouday.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 将配置檔案中的屬性映射到這個元件中
 */
@Component
// @ConfigurationProperties(prefix = "person")
public class Person {
    /**
     * <bean class="Person">
     *     <property name="name" value="Tom" />
     * </bean>
     *
     * value 支援
     * 字面量
     * ${key}從環境變量,配置檔案中擷取值
     * #{SpEL}表達式
     */
    @Value("Tom")
    private String name;

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

    @Value("true")
    private Boolean sex;

    @Value("${person.birth}")
    private Date birth;
    private Map<String, Object> maps;
    private List<String> lists;
    private Dog dog;

    /**
    * 略setter/getter toString()
    */

}
      
Person{name='Tom', age=24, sex=true, birth=Tue Dec 12 00:00:00 CST 2017,
maps=null, lists=null, dog=null}      

配置檔案注入值資料校驗

import org.hibernate.validator.constraints.Email;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
    @Email
    private String name;
}
      

使用方式

  1. 隻是在某個業務邏輯中擷取一個配置檔案中的某項值,使用@Value
  2. 專門編寫一個 javaBean 來映射配置檔案,那麼使用@ConfigurationProperties

@Value 用法示例

package com.mouday.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@Controller
@RestController
public class HelloController {

    @Value("${person.name}")
    private String name;

    @RequestMapping("/hello")
    @ResponseBody
    public String hello(){
        return "Hello world! " + this.name;
    }
}
      

5、@PropertySource、@ImportResource、@Bean

@ConfigurationProperties 預設加載全局配置

5.1、@PropertySource 加載指定配置檔案

import org.springframework.stereotype.Component;
import org.springframework.context.annotation.PropertySource;

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

5.2、@ImportResource 導入 Spring 配置檔案

src/main/resources/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 name="dog" class="com.mouday.bean.Dog"/>
</beans>
      

@ImportResource 标注在配置類上

package com.mouday;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

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

測試方法

package com.mouday;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private ApplicationContext context;

    @Test
    public void TestDog(){
        System.out.println(this.context.containsBean("dog"));
    }
}      

5.3、@Bean 用于配置類中給容器添加元件

package com.mouday.config;

import com.mouday.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Configuration 指明目前類是一個配置類
 * 替代Spring的配置檔案
 */
@Configuration
public class MyConfig {
    // 将方法的傳回值添加到容器,容器中元件預設id是方法名
    @Bean
    public Dog dog(){
        return new Dog();
    }
}
      

Spring 推薦使用全注解方式給容器添加元件

6、配置檔案占位符

RandomValuePropertySource 配置檔案中可以使用随機數

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

屬性配置占位符

app.name=MyApp
app.description=${app.name:預設值}      

7、Profile 多環境支援

Profile 對不同環境提供不同配置功能的支援

1、多 Profile 檔案

application-{profile}.properties

預設使用

application.properties

通過 spring.profiles.active=prod 指定配置檔案

server.port=8080
spring.profiles.active=prod      

application-dev.properties

server.port=8081      

application-prod.properties

server.port=8082      

2、yaml 文檔塊模式

application.yml

server:
  port: 8080
spring:
  profiles:
    active: dev

---
server:
  port: 8081
spring:
  profiles: dev

---
server:
  port: 8082
spring:
  profiles: prod      

8、配置檔案的加載位置

Spring Boot 會自動掃描一下位置的

application.properties 或者 application.yml 檔案作為配置檔案

優先級從高到低,所有檔案都被加載,

互補配置:高優先級覆寫低優先級

./config/
./
classpath:/config/
classpath:/      

spring.config.location 修改預設位置

9、外部配置加載順序

優先級從高到低如下

1. 指令行參數
$ java -jar springboot-helloword-1.0-SNAPSHOT.jar --server.port=8005

2. java:comp/env的JNDI屬性
3. java系統屬性System.getProperties()
4. 作業系統環境變量
5. RandomValuePropertySource配置的random.*屬性
6. jar包外部的application-{profile}.properties或application.yml(帶spring.profile)配置檔案
7. jar包内部的application-{profile}.properties或application.yml(帶spring.profile)配置檔案
8. jar包外部的application.properties或application.yml(不帶spring.profile)配置檔案
9. jar包内部的application.properties或application.yml(不帶spring.profile)配置檔案
10. @Configuration注解類上的@PropertySource
11. 通過SpringApplication.setDefualtProperties指定的預設屬性      

總結:

  1. 高優先級配置會覆寫低優先級配置
  2. 所有配置會形成互補配置

10、自動配置原理

掃描配置檔案内容包裝成 properties 對象

将配置内容加載到容器中

  1. AutoConfiguration 自動配置類
  2. Properties 封裝屬性
  3. @Condition 判斷條件成立,決定配置類是否生效

11、@Conditional&自動配置報告

@ConditionalOnJava
@ConditionalOnMissingBean
@ConditionalOnClass
..      

自動配置類必須在一定的條件下才生效

開啟調試模式

debug=true      

列印自動配置報告

=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches: 啟動的自動配置類
Negative matches: 沒啟用啟動的自動配置類
Exclusions:
Unconditional classes: