【SpringBoot 2學習筆記】《四》配置文件探祕

4.1 配置文件說明

SpringBoot2工程中默認使用全局的配置文件,配置文件名也是固定:application。通過配置文件中配置項的設定,完成SpringBoot2自動配置的默認值的修改,SpringBoot2會在底層自動配置好。配置文件可以有兩種形式:yml和properties。實際上,yml文件的配置與properties文件只是簡寫和縮進方式上面的細微差別,所以本人沿用原來代碼風格,統一使用properties文件進行配置。

  • application.properties

  • application.yml

4.2 YAML介紹

YAML是專注於寫配置文件的語言,這個名字的含義是YAML Ain’t Markup Language(YAML不是一種標記語言),但是實際上YAML還是一種標記語言,只不過是更加聚焦於數據的標記語言。基本語法規則如下:

  • 大小寫敏感
  • 使用縮進表示層級關係
  • 縮進時不允許使用Tab鍵,只允許使用空格。
  • 縮進的空格數目不重要,只要相同層級的元素左側對齊即可
  • # 表示註釋,從這個字符一直到行尾,都會被解析器忽略。

4.2.1 YAML基本語法

**k:(空格)v:**表示鍵值對,注意空格必須有。通過空格的縮進來配置項控制層級關係,左對齊的一列數據屬於同一個層次。屬性和值也是大小寫敏感。

server:
    port: 8081

4.2.2 YAML值的寫法

4.2.2.1、字面量即普通的值(數字,字符串,布爾)

​ k: v:直接按照字面來寫,其中字符串默認不用加上單引號或者雙引號。

“”:雙引號;特殊字符會作爲本身想表示的意思,不會進行轉義

name: “Gavin\n LN SY”:輸出;Gavin換行 LN SY

‘’:單引號;將對特殊字符進行轉義,特殊字符最終只是一個普通的字符串數據

name: ‘Gavin\n LN SY’:輸出;Gavin\n LN SY

4.2.2.2 對象(屬性和值)、Map(鍵值對)

k: v:通過在下一行來寫對象的屬性和值的對應關係,注意縮進方式。對象仍然是K:V的方式,方便閱讀。

users:
		name: Gavin
		age: 28

同時也支持行內寫法:

users: {name: Gavin,age: 18}
4.2.2.3 數組(List、Set)

-值表示數組中的一個元素

animals:
 - cat
 - dog
 - pig
4.2.2.4 複合類型數據
users:
  name: Gavin
  age: 28
  birth: 2017/10/18
  maps:
    school: NEU
    class: 99
  phones:
    ‐ 13909871277
    ‐ 13803451232
  dog:
    name: 二黑
    age: 4

4.3 配置文件內容讀取

配置文件(application.properties)

server.servlet.context-path=/gavin
server.port=9001

user.username=gavin
user.password=gavinpw
user.age=28

4.3.1 ConfigurationProperties 進行屬性綁定(默認配置文件)

從application.properties中讀取前綴爲“user”的配置項目信息,給對應的組件(JavaBean)賦值。

JavaBean代碼

/**
 * 將配置文件中配置的每一個屬性的值,映射到BaseUser組件的元素中
 * 注意:
 * 1. @ConfigurationProperties:通知SpringBoot2將該組件中的所有屬性和配置文件指定的配置項進行綁定
 * 2. prefix = "user":配置文件中指定綁定屬性的元素前綴
 * 3. @Component:該JavaBean需要聲明爲容器中的組件,才能使用的@ConfigurationProperties功能
 *
 */
@Component
@ConfigurationProperties(prefix = "user")
public class BaseUser {
    private String username;
    private String password;
    private int age;

POM文件中需要導入配置文件處理器

<!--導入配置文件處理器,配置文件進行綁定就會有提示-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

在Controller文件中取得對應的屬性值並返回

package com.gavinbj.psbigdata.controller;

import javax.annotation.Resource;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.gavinbj.psbigdata.bean.BaseUser;

@RestController
@RequestMapping("/api")
public class HelloController {
	
    @Resource
    private BaseUser user;

    @GetMapping("/hello")
    public String hello() {
    	
    	System.out.println("使用@ConfigurationProperties讀取配置文件結果:" + user.getUsername() + ": " + user.getPassword());
    	
      return "讀取配置文件成功";
    
    }
}

啓動執行運行結果:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

....... 此處省略啓動內容


2019-11-28 21:09:56.195  INFO 5908 --- [nio-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 4 ms
使用@ConfigurationProperties讀取配置文件結果:gavin: gavinpw

4.3.2 ConfigurationProperties 進行屬性綁定(指定properties文件)

user.properties

user2.username=你好
user2.password=gavinpw
user2.age=28

JavaBean代碼:

/**
 * 將配置文件中配置的每一個屬性的值,映射到BaseUser組件的元素中
 * 注意:
 * 1. @ConfigurationProperties:通知SpringBoot2將該組件中的所有屬性和配置文件指定的配置項進行綁定
 * 2. prefix = "user":配置文件中指定綁定屬性的元素前綴
 * 3. @Component:該JavaBean需要聲明爲容器中的組件,才能使用的@ConfigurationProperties功能
 * 4. @PropertySource: 指定外部配置文件的路徑,配置項中有中文需要指定 encoding = "utf-8"
 */
@Component
@ConfigurationProperties(prefix = "user2")
@PropertySource(
	value = {"user.properties"},
	encoding = "utf-8"
)
public class BaseUser {
    private String username;
    private String password;
    private int age;

啓動執行運行結果:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

....... 此處省略啓動內容


2019-11-28 21:09:56.195  INFO 5908 --- [nio-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 4 ms
使用@ConfigurationProperties讀取配置文件結果:你好: gavinpw

4.3.3 完整數據對應示例

配置文件中(meet.properties)直接對應複雜數據類型,例如:List、Map等

# 簡單的字符串
meet.name=例會
meet.joins=12

# List類型數據
meet.person[0]=張三
meet.person[1]=李四

# Map類型的數據
meet.detail.task=codereview
meet.detail.location=第二會議室

# 時間類型的數據
meet.date=2019/11/28 13:30:30

對應的JavaBean代碼:

// 配置文件前綴爲 meet
@ConfigurationProperties(prefix = "meet")
// 獲取外部的配置文件文件,需要指定配置文件的路徑
@PropertySource(
    ignoreResourceNotFound = true,
    value = "meet.properties",
    encoding = "utf-8"
)
@Component
@Data
public class MeetInfo {
    private String name;
    private int joins;
    private List<String> person;
    private Map<String, String> detail;
    private Date date;
}

啓動執行運行結果:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

....... 此處省略啓動內容


2019-11-28 21:09:56.195  INFO 5908 --- [nio-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 4 ms
使用@ConfigurationProperties讀取配置文件結果:例會: 第二會議室

4.4 @Value獲取值和@ConfigurationProperties獲取值比較

@ConfigurationProperties @Value
功能 批量注入配置文件中的屬性 一個個指定
鬆散綁定(鬆散語法) 支持 不支持
SpEL 不支持 支持
JSR303數據校驗 支持 不支持
複雜類型封裝 支持 不支持

建議:

  • 在某個業務邏輯中需要獲取一下配置文件中的某項值,推薦使用@Value

  • 整體的配置文件和專門的JavaBean進行映射,推薦直接使用@ConfigurationProperties

4.5 Profile文件

4.5.1 多Profile文件

在多個環境中的主配置文件編寫,文件名可以是:application-{profile}.properties。默認使用application.properties的配置。

4.5.2 yml多文檔塊配置

server:
  port: 8081
  
spring:
  profiles:
    active: prod  #指定屬於哪個環境

---
server:
  port: 8092
spring:
  profiles: dev
  
---
server:
  port: 8093
spring:
  profiles: prod 

4.5.3 激活指定profile方式

  • 通過在配置文件中設定:spring.profiles.active=dev
  • 通過命令行參數方式設定:java -jar psbigdata.jar --spring.profiles.active=dev;
  • 通過設定虛擬機參數,優先級大於配置文件:-Dspring.profiles.active=dev

4.6 配置文件加載位置

SpringBoot項目啓動會掃描以下位置的application.properties或者application.yml文件作爲Spring boot的默認配置文件。

  • –file:./config/
  • –file:./
  • –classpath:/config/
  • –classpath:/

說明:優先級由高到底,高優先級的配置會覆蓋低優先級的配置。同時SpringBoot會從這四個位置全部加載主配置文件,並採用並集互補的方式合成配置項的讀取。還可以通過spring.config.location來改變默認的配置文件位置。

如果使用命令行參數的形式,啓動項目的時候來指定配置文件的新位置優先級大於配置文件,同時命令行參數指定配置文件和默認加載的這些配置文件共同起作用形成互補配置。

其他說明請參考官方文檔

4.7 自動配置原理說明

官網配置文件能配置的屬性參照

  1. SpringBoot啓動的時候加載主配置類,開啓了自動配置功能 @EnableAutoConfiguration
  2. @EnableAutoConfiguration作用
    • 利用EnableAutoConfigurationImportSelector給容器中導入組件
    • 可以查看selectImports()方法的內容
    • 獲取候選的配置
  3. 以**HttpEncodingAutoConfiguration(Http編碼自動配置)**爲例解釋自動配置原理;
// 表示是一個配置類,也可以給容器中添加組件
@Configuration

// 啓動指定類的ConfigurationProperties功能,並將配置文件中對應的值和HttpEncodingProperties綁定起來
// 並把HttpEncodingProperties加入到ioc容器中
@EnableConfigurationProperties(HttpEncodingProperties.class)  

// Spring底層@Conditional註解,根據不同的條件,如果滿足指定的條件,整個配置類裏面的配置就會生效
// 判斷當前應用是否是web應用,如果是,當前配置類生效
@ConditionalOnWebApplication 

// 判斷當前項目有沒有這個類CharacterEncodingFilter(SpringMVC中進行亂碼解決的過濾器)
@ConditionalOnClass(CharacterEncodingFilter.class)  

// 判斷配置文件中是否存在某個配置(spring.http.encoding.enabled),如果不存在,判斷也是成立的
// 即使我們配置文件中不配置pring.http.encoding.enabled=true,也是默認生效的
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)  
public class HttpEncodingAutoConfiguration {
  
  	// SpringBoot的配置文件映射
  	private final HttpEncodingProperties properties;
  
    // 參數的值從指定的有參構造器中取得
  	public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
		this.properties = properties;
	}
  
  // 在容器中添加一個組件,該組件的某些值需要從properties中獲取
  @Bean   
	@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;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章