1. 程式人生 > >微服務 SpringBoot 2.0(二):配置檔案解析

微服務 SpringBoot 2.0(二):配置檔案解析

properties我用了好多年,你卻讓我用yml,這是什麼鬼 —— Java面試必修

引言

上一篇介紹了Spring Boot的輕鬆入門專案構建,對Spring Boot的特性有了初步瞭解。但如果要想玩得很熟練的話就請看接下來的文章,這樣有助於後續我們快速的構建企業級應用,打怪咱得先熟悉地圖對吧

配置詳解

工具

  • SpringBoot版本:2.0.4
  • 開發工具:IDEA 2018
  • Maven:3.3 9
  • JDK:1.8

配置檔案型別

本文主要講解SpringBoot的配置檔案,常用的配置檔案型別有如下兩種,分為properties、yml,先甭管什麼檔案,SpringBoot都能正確載入讀取裡面的引數,配置檔案的路徑在:src/main/resources

  1. properties結尾的檔案,這種想必大家都比較熟悉了,比如:jdbc.properties,或log4j.properties
  2. yml結尾的檔案,YAML(Yet Another Markup Language)結構化的資料配置檔案,諧音(亞妹襖),ML和XML同音

動手嘗試

  1. 2種配置均可讀取的固定程式碼,配置請往下看
@RestController
@SpringBootApplication
public class DemoApplication {

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

	@Value(
"${com.demo.url}") private String url; @RequestMapping("/index") public String index(){ return "name:" + name +",url:" + url ; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
  1. application.properties,先來個簡單的配置,程式碼@Value註解直接繫結
com.demo.name="JAVA面試必修"
com.demo.url="www.itmsbx.com"
結果:成功返回name:“Java面試必修”,url:"www.itmsbx.com"
  1. 換成 application.yml 則內容如下
#註釋
com.demo.name: Java面試必修
com.demo.url: www.itmsbx.com

---- yml上下任選一種即可

com.demo:
  name: Java面試必修
  url: www.itmsbx.com
結果:name:Java面試必修,url:www.itmsbx.com

Spring框架提供兩個便利的類用於載入YAML文件,YamlPropertiesFactoryBean會將YAML載入為PropertiesYamlMapFactoryBean會將YAML載入為Map,後續講解

Bean物件繫結

認識了配置檔案後,我們發現yml中的資料繫結還挺好用的。但是問題來了,一個個繫結到屬性欄位上太累,能換成物件,咱們就使用物件對吧,那也是可以的,我們建一個DemoBean.java類。

  1. Bean類中使用註解 @ConfigurationProperties(prefix = “com.demo”)來指明繫結配置檔案中哪個變數
@ConfigurationProperties(prefix = "com.demo")
public class DemoBean {

    //省略getter和setter
    private String name;
    private String url;

}

  1. Controller中使用註解@EnableConfigurationProperties({DemoBean.class})來繫結實體類,並使用Autowired在成員變數處注入即可
@RestController
@SpringBootApplication
@EnableConfigurationProperties({DemoBean.class})
public class DemoApplication {

	@Autowired
	DemoBean demoBean;


	@RequestMapping("/index")
	public String index(){
		return "name:" + demoBean.getName() + ",url:" + demoBean.getUrl();
	}

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);

	}
}
結果:name:Java面試必修,url:www.itmsbx.com

引數與引數間的引用

# 註釋
com.demo:
  name: Java面試必修
  url: www.itmsbx.com
  scope: ${com.demo.name}的網址是${com.demo.url}

這樣我們直接使用scope屬性就能看到效果了,注:properties和yml除了書寫格式上的差異外,使用方式基本類似,所以後續我們的講解中都建議使用yml檔案

隨機引數生成

通常是用這些隨機數我們得寫一段程式碼生成,現在配置檔案中${random} 可以用來生成各種不同型別的隨機值,從而簡化了程式碼生成的麻煩,例如 生成 int 值、long 值或者 string 字串

demo.secret: ${random.value}
demo.number: ${random.int}
demo.bignumber: ${random.long}
demo.uuid: ${random.uuid}
demo.number.less.than.ten: ${random.int(10)}
demo.number.in.range: ${random.int[1024,65536]}

大家仔細思考下,${}很熟悉,我們用自己的變數也是${}包含起來的對不對,那其實這是SpringBoot已經封裝好的配置變數啦,類似於jsp中的隱式物件request一樣,拿來即用

命令列引數配置

Spring Boot是基於jar包執行的,打成jar包的程式可以直接通過下面命令執行:

java -jar demo-0.0.1-SNAPSHOT.jar

可以使用下命令修改tomcat埠號:

java -jar demo-0.0.1-SNAPSHOT.jar --server.port=9090

等價於在yml中配置server.port: 9090,或properties中配置server.port=9090
java -jar demo-0.0.1-SNAPSHOT.jar

控制檯輸出

$ java -jar myapp.jar --debug
但前提是你需要在yml或properties中指明 debug=true

設定Spring profiles引數啟動

$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar

命令啟動引數用 --xxx=xxx 的形式傳遞。命令列引數在demo.jar的後面,如果你擔心命令列有風險,則可以使用SpringApplication.setAddCommandLineProperties(false)禁用它。

執行或系統引數獲取

Spring Boot應用程式有多種設定途徑,Spring Boot能從多重屬性源獲得屬性,包括如下幾種(優先順序從高到低排序):

  • 命令列引數
  • SPRING_APPLICATION_JSON中的屬性(環境變數或系統屬性中的內聯JSON嵌入)。
  • ServletConfig初始化引數。
  • ServletContext初始化引數。
  • 來自java:comp/env的JNDI屬性
  • Java系統屬性(System.getProperties()
  • 作業系統環境變數
  • RandomValuePropertySource配置的random.*屬性值,比如${random.long}
  • jar包外部的application-{profile}.propertiesapplication.yml(帶spring.profile)配置檔案
  • jar包內部的application-{profile}.propertiesapplication.yml(帶spring.profile)配置檔案
  • jar包外部的application.propertiesapplication.yml(不帶spring.profile)配置檔案
  • jar包內部的application.propertiesapplication.yml(不帶spring.profile)配置檔案
  • @Configuration註解類上的@PropertySource
  • 通過SpringApplication.setDefaultProperties指定的預設屬性

任何在高優先順序屬性源裡設定的屬性都會覆蓋低優先順序的相同屬性,列如我們上面提到的命令列屬性就覆蓋了application.properties的屬性。

配置檔案的優先順序

application.propertiesapplication.yml檔案可以放在以下四個位置:

  • 外接,在相對於應用程式執行目錄的/congfig子目錄裡。
  • 外接,在應用程式執行的目錄裡
  • 內建,在config包內
  • 內建,在Classpath根目錄

同樣,這個列表按照優先順序排序,也就是說,src/main/resources/config/application.properties覆蓋src/main/resources/application.properties中相同的屬性,如圖:
配置檔案優先順序

此外,如果你在相同優先順序位置同時有application.propertiesapplication.yml,那麼application.properties裡的屬性裡面的屬性就會覆蓋application.yml

使用自定義的配置檔案

對於同時載入多個properties配置檔案,SpringBoot有註解@PropertySource支援,而yml多配置檔案需要單獨用程式讀取,官方提供了YamlPropertySourceLoader.java類來支援,所以**@PropertySource只能支援properties配置檔案**,如下:

@Configuration
@ConfigurationProperties(prefix = "com.custom")
@PropertySource("classpath:application-test.properties")
public class CustomBean {

    //省略getter和setter
    private String sex;
    private String age;
    private String desc;
    
}

若對於yml多配置檔案,建議寫到一個裡面,但如果分成多個環境載入不同配置,那接下來我們就講解下如何通過命令引數呼叫不同的yml

Profile-多環境配置

普通springmvc專案解決方案

在普通的springmvc的tomcat專案中,我們也可以指定JVM的執行引數,在啟動服務的時候通過System.getProperty(“JVM配置key”)獲取到這個引數,然後初始化不同的Properties檔案,操作如下:
普通springmvc專案,properties檔案

	<!-- 從properties檔案載入配置資訊 -->
	<bean id="propertyPlaceholderConfigurer" class="com.xx.xx.common.spring.CustomizedPropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<!-- 此處配置檔案需要在tomcat執行引數中指定[develop|test|product]其中一個,若不指定,預設取develop -->
				<value>classpath*:**/config/config-develop.properties</value>
				<value>classpath*:**/config/config-test.properties</value>
				<value>classpath*:**/config/config-product.properties</value>
			</list>
		</property>
		<property name="configureClasses">
			<list>
				<value>com.xx.xx.common.util.Constants</value>
			</list>
		</property>
	</bean>

    tomcat 中 catalina.bat(.sh中不用“set”) 新增JAVA_OPS。通過設定active選擇不同配置檔案
    set JAVA_OPTS="-Dspring.profiles.active=test"

上述的CustomizedPropertyPlaceholderConfigurer類實現了PropertyPlaceholderConfigurer,在初始化的時候通過獲取JVM的profile進行不同的properties選取

SpringBoot解決方案

對於多環境的配置,各種專案構建工具或是框架的基本思路是一致的,通過配置多份不同環境的配置檔案,再通過打包命令指定需要打包的內容之後進行區分打包,Spring Boot也不例外,或者說更加簡單。

在Spring Boot中多環境配置檔名需要滿足application-{profile}.yml的格式,其中{profile}對應你的環境標識,如下圖:

yml結構

至於哪個具體的配置檔案會被載入,需要在application.yml檔案中通過spring.profiles.active屬性來設定,其值對應{profile}值。如:spring.profiles.active=prod就會載入application-prod.yml配置檔案內容

application.yml內容如下

spring.profiles.active: dev

application-dev.yml內容如下

server:
  port: 1000

application-prod.yml內容如下

server:
  port: 1001

啟動的時候帶上引數:java -jar xxx.jar --spring.profiles.active=dev,就會發現啟動的埠不一樣,說明配置檔案生效了

程式碼使用profile

除了可以用profile的配置檔案來分割槽配置我們的環境變數,在程式碼裡,我們還可以直接用@Profile註解來進行配置,例如資料庫配置,這裡我們先定義一個介面

public  interface DBConnector { public  void  dbConfig(); }

分別定義倆個實現類來實現它

/**
  * 開發資料庫
  */
@Component
@Profile("devdb")
public class DevDBConnector implements DBConnector {
    @Override
    public void dbConfig() {
        System.out.println("devdb");
    }
}
/**
 * 生產資料庫
 */
@Component
@Profile("prodb")
public class ProDBConnector implements DBConnector {
    @Override
    public void dbConfig() {
        System.out.println("prodb");
    }
}

通過在配置檔案啟用具體使用哪個實現類

spring.profiles.active=prodb

然後具體呼叫如下

@RestController
@RequestMapping("/call")
public class CallController {

    @Autowired DBConnector connector ;

    @RequestMapping(value = {"/",""})
    public String hellYml(){

        connector.dbConfig(); //最終列印prodb
        return "Hello yml";
    }
}

總結

SpringBoot的配置檔案給我們帶來了極大的便利,properties和yml兩者各選一個吧,不過我更傾向於yml,其格式化的配置看起來很舒服,有點類似於json格式,更多的屬性及配置後續在使用的過程中慢慢講解。

作者有話說:喜歡的話就請移步Java面試必修網,請自備水,更多幹、幹、乾貨等著你