Spring Boot配置文件

1、基本介紹

  Spring Boot提供了兩種經常使用的配置文件,分別是properties文件和yml文件。html

  • application.properties
  • application.yml

  他們的做用都是修改Spring Boot自動配置的默認值。相對於properties文件而言,yml文件更年輕,也有不少的坑。可謂成也蕭何敗也蕭何,yml經過空格來肯定層級關係,使配置文件結構更清晰,但也會由於微不足道的空格而破壞了層級關係。java

2、YAML簡介

yml是YAML(YAML Ain't Markup Language)語言的文件,以數據爲中心,比json、xml等更適合作配置文件程序員

  之前的配置文件;大多都使用的是 xxxx.xml文件;yml和xml相比,少了一些結構化的代碼,使數據更直接,一目瞭然。舉例:spring

  YAMLsql

server:
  port: 8081

  XML:json

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

  yml和json呢?沒有誰好誰壞,合適纔是最好的。yml的語法比json優雅,註釋更標準,適合作配置文件。json做爲一種機器交換格式比yml強,更適合作api調用的數據交換。api

2.1 YAML的語法

  k:(空格)v:表示一對鍵值對(空格必須有);數組

  以空格的縮進程度來控制層級關係。空格的個數並不重要,只要左邊空格對齊則視爲同一個層級。注意不能用tab代替空格。且大小寫敏感。springboot

server:
    port: 8081
    path: /hello

  YAML支持字面值,對象,數組三種數據結構,也支持複合結構。數據結構

【字面值】——字符串,布爾類型,數值,日期。

  k: v:字面直接來寫;

  字符串默認不用加上單引號或者雙引號;

  "":雙引號;不會轉義字符串裏面的特殊字符;特殊字符會做爲自己想表示的意思

name:   "zhangsan \n lisi":輸出;zhangsan 換行  lisi

  '':單引號;會轉義特殊字符,特殊字符最終只是一個普通的字符串數據

name:   ‘zhangsan \n lisi’:輸出;zhangsan \n  lisi

【對象】

  由鍵值對組成,形如 key:(空格)value 的數據組成。冒號後面的空格是必需要有的,每組鍵值對佔用一行,且縮進的程度要一致。

friends:
        lastName: zhangsan
        age: 20

  也可使用行內寫法:{k1: v1, ....kn: vn}

friends: {lastName: zhangsan,age: 18}

【數組】——List、Set

  由形如 -(空格)value 的數據組成。短橫線後面的空格是必需要有的,每組數據佔用一行,且縮進的程度要一致,也可使用行內寫法: [1,2,...n]

pets:
 - cat
 - dog
 - pig

  行內寫法

pets: [cat,dog,pig]

2.2 YAML的運用

  建立一個Spring Boot 的全局配置文件 application.yml,配置屬性參數。

person:
  lastName: hello
  age: 18
  boss: false
  birth: 2019/7/14
  maps: {k1: v1,k2: v2}
  lists:
    - zhangsan
    - lisi
  dog:
    name: 小狗
    age: 12

  建立實體類Person.java 獲取配置文件中的屬性值,經過註解@ConfigurationProperties獲取配置文件中的指定值並注入到實體類中。

/**
 * 將配置文件中配置的每個屬性的值,映射到這個組件中
 * @ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定;
 *      prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射
 *
 * 只有這個組件是容器中的組件,才能容器提供的@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;

    // 省略getter,setter,toString方法  
}

  咱們能夠導入配置文件處理器,之後編寫配置就有提示了

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

  建立一個單元測試類:

/**
 * SpringBoot單元測試;
 *
 * 能夠在測試期間很方便的相似編碼同樣進行自動注入等容器的功能
 *
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonTest {
    @Autowired
    private Person person;

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

img

  注意:在運行測試類以前,要確保spring boot的引導類(主程序)是已啓動狀態。

2.3 YML小結

  1. 字符串能夠不加引號,若加雙引號則輸出特殊字符,若不加或加單引號則轉義特殊字符;
  2. 數組類型,短橫線後面要有空格;對象類型,冒號後面要有空格;
  3. YAML是以空格縮進的程度來控制層級關係,但不能用tab鍵代替空格,大小寫敏感;
  4. 如何讓一個程序員崩潰?在yml文件中加幾個空格!

3、Properties簡介

  properties文件常常用,這裏就簡單介紹一下。其語法結構形如:key=value。

userinfo.account=zhangsan
userinfo.age=25
userinfo.active=true
userinfo.created-date=2019/07/14 16:54:30
userinfo.map.k1=v1
userinfo.map.k2=v2
userinfo.list=one,two,three

  從配置文件中取值注入到實體類中,和YAML是同樣的。

/**
 * 用戶信息
 * @ConfigurationProperties : 被修飾類中的全部屬性會和配置文件中的指定值(該值經過prefix找到)進行綁定
 */
@Component
@ConfigurationProperties(prefix = "userinfo")
public class UserInfo {

    private String account;
    private Integer age;
    private Boolean active;
    private Date createdDate;
    private Map<String, Object> map;
    private List<Object> list;

   // 省略getter,setter,toString方法
}

   注意:properties配置文件在idea中默認utf-8可能會亂碼。調整以下:

img

  【注意】:spring boot項目中同時存在application.properties和application.yml文件時,兩個文件都有效,可是application.properties的優先級會比application.yml高。

4、配置文件取值

  Spring Boot經過ConfigurationProperties註解從配置文件中獲取屬性。從上面的例子能夠看出ConfigurationProperties註解能夠經過設置prefix指定須要批量導入的數據。支持獲取字面值,集合,Map,對象等複雜數據。ConfigurationProperties註解還有其餘特麼呢?它和Spring的Value註解又有什麼區別呢?帶着這些問題,咱們繼續往下看。

4.1 ConfigurationProperties和Value對比

img

  ConfigurationProperties註解的優缺點

  1. 能夠從配置文件中批量注入屬性;
  2. 支持獲取複雜的數據類型;
  3. 對屬性名匹配的要求較低,好比user-name,user_name,userName,USER_NAME均可以取值;
  4. 支持JAVA的JSR303數據校驗;
  5. 缺點是不支持強大的SpEL表達式;

  Value註解的優缺點正好相反,它只能一個個配置注入值;不支持數組、集合等複雜的數據類型;不支持數據校驗;對屬性名匹配有嚴格的要求。最大的特色是支持SpEL表達式,使其擁有更豐富的功能。  

4.2 @ConfigurationProperties詳解

  第一步:導入依賴。若要使用ConfigurationProperties註解,須要導入依賴 spring-boot-configuration-processor;

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

   第二步:配置數據。在application.yml配置文件中,配置屬性參數,其前綴爲employee,參數有字面值和數組,用來判斷是否支持獲取複雜屬性的能力;(nick-name是用來判斷匹配屬性的鬆散性,若換成nick_name依然能夠獲取值。)

employee:
  nick-name: itachi
  email: 123456@126.com
  phone: 1234567
  abilities: [java,sql,html]
  created_date: 2019/7/14 13:40

  第三步:匹配數據。在類上添加註解ConfigurationProperties,並設置prefix屬性值爲employee。並把該類添加到Spring的IOC容器中。

  第四步:校驗數據。添加數據校驗Validated註解,開啓數據校驗,測試其是否支持數據校驗的功能;

  第五步:測試ConfigurationProperties註解是否支持SpEL表達式;

/**
 * ConfigurationProperties 註解語法類
 * 第一步:導入依賴 spring-boot-configuration-processor;
 * 第二步:把ConfigurationProperties註解修飾的類添加到Spring的IOC容器中;
 * 第三步:設置prefix屬性,指定須要注入屬性的前綴;
 * 第四步:添加數據校驗註解,開啓數據校驗;
 *
 * 注意點:
 * 1、nickName和createdDate在yml配置文件中,對應參數分別是中劃線和下劃線,用於測試其對屬性名匹配的鬆散性
 * 2、email和iphone 測試其支持JSR303數據校驗
 * 3、abilities 測試其支持複雜的數據結構
 */
@Component
@ConfigurationProperties(prefix = "employee")
@Validated
public class ConfigurationPropertiesEntity {
    private String nickName; // 解析成功,支持鬆散匹配屬性
    private String email;
    // @Email //表示phone必須填成email格式。此處解析失敗:Binding validation errors on employee
    private String phone;
    private List<String> abilities;
    private Date createdDate; // 解析成功,支持鬆散匹配屬性

    // @ConfigurationProperties("#{11*2}") //語法報錯,不支持SpEL表達式:not applicable to field
    private String operator;

   // 省略get/set和toString方法  
}

4.3 @Value詳解

  第一步:在屬性上添加Value註解,經過${}設置參數從配置文件中注入值;

  第二步:修改${employee.ceatred_date}中的參數值,改成${employee.ceatredDate}測試是否能解析成功;

  第三步:添加數據校驗Validated註解,開啓數據校驗,測試其是否支持數據校驗的功能;

  第四步:測試Value註解是否支持SpEL表達式;

/**
 * Value 註解語法類
 * 第一步:在屬性上添加註解Value注入參數
 * 第二步:把Value註解修飾的類添加到Spring的IOC容器中;
 * 第三步:添加數據校驗註解,檢查是否支持數據校驗;
 *
 * 注意點:
 * 1、nickName和createdDate在yml配置文件中,對應參數分別是中劃線和下劃線,用於測試其對屬性名匹配的鬆散性
 * 2、email和iphone 測試其支持JSR303數據校驗
 * 3、abilities 測試其支持複雜的數據結構
 *
 * 結論:
 * 1、createDate取值必須和yml配置文件中的參數保持一致,
 * 2、既是在iphone上添加郵箱驗證註解依然能夠經過測試,
 * 3、不支持複雜的數據結構,提示錯誤和第一條相同:IllegalArgumentException: Could not resolve placeholder 'itdragon.abilities' in value "${itdragon.abilities}"
 */
@Component
@Validated
public class ValueEntity {
    @Value("${employee.nick-name}")
    private String nickName;
    @Value("${employee.email}")
    private String email;
    @Email
    @Value("${employee.phone}") // 解析成功,並不支持數據校驗
    private String phone;
    // @Value("${employee.abilities}") //解析錯誤,並不支持複雜的數據結構
    private List<String> abilities;
    // @Value("${employee.createDate}") // 解析錯誤,並不支持鬆散匹配屬性,必須嚴格一致
    @Value("${employee.created_date}")
    private Date createDate;

    // Value註解的強大一面:支持SpEL表達式
    @Value("#{11*2}") // 算術運算
    private String operator;

    @Value("#{1>2 || 2<=3}") // 關係運算
    private Boolean comparison;

    @Value("#{systemProperties['java.version']}") //系統配置:os.name
    private String systemProperties;

    @Value("#{T(java.lang.Math).abs(-18)}") // 表達式
    private String mapExpression;
   
    // 省略get/set和toString()
}

4.4 配置文件取值小結

  1. ConfigurationProperties註解支持批量注入,而Value註解適合單個注入;
  2. ConfigurationProperties註解支持數據校驗,而Value註解不支持;
  3. ConfigurationProperties註解支持鬆散匹配屬性,而Value註解必須嚴格匹配屬性;
  4. ConfigurationProperties不支持強大的SpEL表達式,而Value支持;

  若是說,咱們只是在某個業務邏輯中須要獲取一下配置文件中的某項值,使用@Value;

  若是說,咱們專門編寫了一個javaBean來和配置文件進行映射,咱們就直接使用@ConfigurationProperties;

5、@PropertySource&@ImportResource&@Bean

5.1 @PropertySource

  @ConfigurationProperties註解默認只能讀取系統全局的配置文件,要加載非全局的配置,須要使用@PropertySource加載文件。@PropertySource的目的是加載指定的屬性文件。

  好比定義一個person.properties

person.last-name=李四
person.age=12
person.birth=2019/7/14
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=dog
person.dog.age=15

  若是要在配置類中加載person.properties配置文件,則須要用到@PropertySource

/**
 * 將配置文件中配置的每個屬性的值,映射到這個組件中
 * @ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定;
 *      prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射
 *
 * 只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能;
 *  @ConfigurationProperties(prefix = "person")默認從全局配置文件中獲取值;
 *
 */
@PropertySource(value = {"classpath:person.properties"})
@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;

    // 省略get/set和toString()方法
}

5.2 @ImportResource

  編寫一個HelloService.java

public class HelloService {
}

  編寫一個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.pinyougou.service.HelloService"></bean>
</beans>

  在測試類中測試該配置文件有沒有生效:

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

    @Autowired
    private ApplicationContext context;

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

  測試代表,Spring Boot裏面沒有Spring的配置文件,咱們本身編寫的配置文件,也不能自動識別;

  想讓Spring的配置文件生效,加載進來;可使用@ImportResource標註在一個配置類上:

@ImportResource(locations = {"classpath:beans.xml"})
@SpringBootApplication
public class SpringbootdemoApplication {

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

  這時候再次運行testHelloService()測試方法,結果爲true。說明本身編寫的beans.xml配置文件已經生效了。

  總結:@ImportResource的做用是:導入Spring的配置文件,讓配置文件裏面的內容生效;

5.3 @Bean

  雖然使用@ImportResource能導入咱們編寫的配置文件,可是SpringBoot並不推薦這種方式,SpringBoot推薦使用全註解的方式來給容器中添加組件。這時候就使用到了@Bean來給容器中添加組件。

  爲了測試效果明顯,將beans.xml刪掉,而且將@ImportResource註釋掉:

img

  建立一個配置類:

/**
 * @Configuration:指明當前類是一個配置類;就是來替代以前的Spring配置文件。@Configuration可理解爲用spring的時候xml裏面的<beans>標籤。
 * @Configuration標註在類上,至關於把該類做爲spring的xml配置文件中的<beans>,做用爲:配置spring容器(應用上下文對象) 
 */
@Configuration
public class MyAppConfig {

    // 將方法的返回值添加到容器中;容器中這個組件默認的id就是方法名   // @Bean標註在方法上(返回某個實例的方法),等價於spring配置文件中的<bean></bean>,做用爲:註冊bean對象
    // @Bean可理解爲用spring的時候xml裏面的<bean>標籤。  
    @Bean
    public HelloService helloService() {
        System.out.println("配置了@Bean給容器中添加了組件。。。");
        return new HelloService();
    }
}

  再次運行測試類:

  img

  注意:

  1. @Bean註解在返回實例的方法上,若是未經過@Bean指定bean的名稱,則默認與標註的方法名相同;
  2. @Bean註解默認做用域爲單例singleton做用域,可經過@Scope(「prototype」)設置爲原型做用域;
  3. 既然@Bean的做用是註冊bean對象,那麼徹底可使用@Component、@Controller、@Service、@Repository等註解註冊bean(在須要註冊的類上加註解),固然須要配置@ComponentScan註解進行自動掃描。

  Spring Boot不是spring的增強版,因此@Configuration和@Bean一樣能夠用在普通的spring項目中。

6、配置文件佔位符

  佔位符和隨機數比較簡單,這裏就直接貼出代碼。須要注意的是:

  • 佔位符的值必須是完整路徑
  • 佔位符設置默認值,冒號後面不能有空格
ran:  # 這裏的prefix不能是random,
  ran-value: ${random.value}
  ran-int: ${random.int}
  ran-long: ${random.long}
  ran-int-num: ${random.int(10)}
  ran-int-range: ${random.int[10,20]}
  ran-placeholder: placeholder_${ran.ran-value:此處不能有空格,且key爲完整路徑} 
/**
 * 隨機數和佔位符語法類
 */
@Component
@ConfigurationProperties(prefix = "ran")
public class RandomEntity {

    private String ranValue;    // 隨機生成一個字符串
    private Integer ranInt;     // 隨機生成一個整數
    private Long ranLong;       // 隨機生成一個長整數
    private Integer ranIntNum;  // 在指定範圍內隨機生成一個整數
    private Integer ranIntRange;// 在指定區間內隨機生成一個整數
    private String ranPlaceholder;// 佔位符

    // 省略getter,setter,toString方法e
}

  測試代碼:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootYmlApplicationTests {
    @Autowired
    private RandomEntity randomEntity;

    @Test
    public void contextLoads() {
        System.out.println("Random Grammar : " + randomEntity);
    }

}

7、Profile多環境支持

7.1 使用properties做爲配置文件時

  咱們在主配置文件編寫的時候,文件名能夠是 application-{profile}.properties。如:

  application-dev.properties

  img

  application-prod.properties

  img

  application.properties主配置文件

  img

  運行主程序時,默認使用的是application.properties主配置文件的端口號:8080

  當咱們要激活指定的profile時,好比要激活開發環境的8081端口,能夠在主配置文件中添加spring.profiles.active=dev

  img

7.2 使用yml做爲配置文件時

  yml支持多文檔塊方式

server:
  port: 8080
spring:
  profiles:
    active: prod #指定使用生產環境運行
---
server:
  port: 8081
spring:
  profiles: dev
---
server:
  port: 8082
spring:
  profiles: prod

7.3 激活指定的profile

  除了在配置文件中經過代碼來激活指定的profile,還能夠經過命令行和指定虛擬機參數的方式來激活指定的profile。

【命令行】

  能夠直接在測試的時候,配置傳入命令行參數:

  img

  此外,若是將項目package後,也能夠經過命令行的方式來指定profile:

  img

【虛擬機參數】

img

8、配置文件的加載路徑及順序

  springboot 啓動會掃描如下位置的application.properties或者application.yml文件做爲Spring boot的默認配置文件

  1. 工程根目錄的config目錄:file:./config/
  2. 工程根目錄:file:./
  3. 類路徑的config目錄:classpath:/config/
  4. 類路徑:classpath:/

  若是存在多個配置文件,則嚴格按照優先級進行覆蓋,最高者勝出。以下圖1~4優先級從高到低:

   img

  SpringBoot會從這四個位置所有加載主配置文件;互補配置

  咱們還能夠經過spring.config.location來改變默認的配置文件位置。

  項目打包好之後,咱們可使用命令行參數的形式,啓動項目的時候來指定配置文件的新位置;指定配置文件和默認加載的這些配置文件共同起做用造成互補配置;

java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties

 

 

 

參考:http://www.javashuo.com/article/p-etzrtvbr-ge.html

相關文章
相關標籤/搜索