SpringBoot(二)—— 配置

SpringBoot系列文章

1. 配置文件

SpringBoot使用一個全局的配置文件,配置文件名是固定的

  • application.properties
  • application.uml

配置文件的作用:對一些默認配置進行修改
配置文件放在src/main/resources目錄或者類路徑/config下

2. YAML

YAML(YAML Ain’t Markup Language)。以前的配置文件大多都是用的是XXX.xml文件,SpringBoot中,也可以使用.yml文件作爲配置文件。.xml文件中,大量的數據都用在了標籤上面,而YAML,是以數據爲中心的,比json、xml等更適合做配置文件。比如,修改端口號

  • xml:
<server> 
	<port>8081</port> 
 </server
  • YAML
server:   
	port: 8081

2.1 YAML 基本語法

  • key: value 表示一對鍵值對,注意冒號後面必須有空格,以空格的縮進來控制層級關係,只要是左對齊的一列數據,就是同一層級
  • 縮進時不允許使用Tab鍵,只允許使用空格,空格數目不重要,只要相同層級的元素左側對其即可
  • 大小寫敏感

值的寫法

  • 普通值(數字、字符串、布爾、日期類型)

直接使用 key: value的形式,注意字符串不用加雙引號或者單引號,當使用雙引號時,可以使用轉義字符,會按照轉移字符的意思輸出
比如name: “zhangsan\nlisi” ,輸出zhangsan 換行 lisi,如果換成單引號的話,會輸出zhangsan/nlisi

  • 對象、Map類型

key: value,在下一行寫對象的屬性和值的關係,注意縮進,比如

friends:
   name: zhangsan
   age: 20

行內寫法

friends: {name: zhangsan,age: 20}
  • 數組(List、Set)
pets:
  ‐ cat
  ‐ dog
  ‐ pig

行內寫法

pets: [cat,dog,pig]

3. SpringBoot 屬性注入

3.1使用YAML進行值注入

person類

/*
將配置文件中配置的每一個屬性的值,映射到這個組件中
  @ConfigurationProperties:告訴SpringBoot將本類中的所有屬性和配置文件中相關的配置進行綁定;
      prefix = "person":配置文件中哪個下面的所有屬性進行一一映射
 
  只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能;
  @ConfigurationProperties(prefix = "person")默認從全局配置文件中獲取值;
 */
@Component
@ConfigurationProperties(prefix="person")
public class Person {
    private String name;
    private int age;
    private Map<String,String> map;
    private List<Object> list;
    private Dog dog;
    get、set方法,toString方法
 }
 public class Dog {
    private String name;
	get、set toString方法
}

application.yml文件

person:
   name: 張三
   age: 20
   map:
     k1: s1
     k2: s2
   list:
     - wangwu
     - lisi
   dog:
     name: mm

導入配置文件處理器,以後編寫配置就有提示了

<!--導入配置文件處理器,編寫配置文件的時候會有提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

3.2 使用properties文件進行屬性注入

application.properties文件

person.name=ewen
person.age=23
person.map.k1=t1
person.map.k2=t2
person.list=[張三]
person.dog.name=nn

使用application.properties文件進行屬性注入,和上面使用application.yml文件使用的註解一樣
注意:idea中使用的是utf-8的編碼格式,而properties使用的是ASCII碼,需要設置一下,settings->File Encoding
在這裏插入圖片描述

3.3 使用@Value 進行屬性注入

可以使用@Value 註解代替@ConfigurationProperties,使用方法和是spring中的一樣,value中可以是值,${.properties屬性文件中的屬性名}
#{SpEL}(spring表達式,裏面可以寫具體的計算)

@Component
//@ConfigurationProperties(prefix="person")
public class Person {
    @Value("王五")
    private String name;
    @Value("${person.age}")// @Value("#{11 * 2}")
    private int age;
    private Map<String,String> map;
    private List<Object> list;
    private Dog dog;

3.4 @Value 和 @ConfigurationProperties 的區別

@ConfigurationProperties @Value
功能 批量注入配置文件中的值 一個一個的注入
鬆散綁定(鬆散語法) 支持 不支持
SpEL 不支持 支持
JSR303 數據校驗 支持 不支持
複雜類型封裝 支持 不支持
  • .yml文件和.properties文件都是使用的@ConfigurationProperties註解
  • 如果說是在某個業務邏輯中需要獲取一下配置文件中的某項值,使用@Value;
  • 如果專門編寫了一個javaBean來和配置文件進行映射,我們就直接使用@ConfigurationProperties;

3.5 @PropertyResource 和 @ImportSource

  • @PropertyResource
    加載指定的配置文件到環境變量中,配置文件只能是.properties文件,不能是.yml文件,就可以不用將對象的屬性值寫在主配置文件中了,使用@PropertyResource之後,還是需要使用@ConfigurProperties進行數據綁定。
@PropertySource(value="classpath:/person.properties")//加載指定的配置文件
@Component
@ConfigurationProperties(prefix="person")
public class Person {
	...}
  • @ImportSource
    導入Spring的配置文件,讓配置文件裏面的內容生效。SpringBoot裏面沒有Spring的配置文件,我們自己編寫的配置文件,也不能自動識別,想讓Spring的配置文件生效,加載進來,使用@ImportResource標註在一個配置類上
@ImportResource(locations = "classpath:/beans.xml") //讓spring的配置文件生效
@SpringBootApplication
public class Springboot01Application {
	... }

SpringBoot推薦使用全註解的方式給容器中添加組件

@Configuration //指明當前類是一個配置類,用配置類代替spring中的xml配置文件
public class MyConfig {
    @Bean//將方法的的返回值添加到容器中,容器中這個組件的id就是方法名
    public HelloService helloService2(){
        System.out.println("配置類給容器添加組件");
        return new HelloService();
    }
}

4. 配置文件佔位符

  • 隨機數:在配置文件中,可以使用${random. }來給屬性一個隨機數
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
  • 可以使用佔位符獲取前面屬性的值,如果沒有前面的屬性,可以使用:默認值,來指定默認值,不指定會報錯
#name爲張三隨機值
person.name=張三${random.uuid} 
#爲age生成一個隨機數
person.age=${random.int} 
person.map.k1=t1
person.map.k2=t2
person.list=張三,李四
#獲取person.hello的值,如果沒有指定默認值爲mm
person.dog.name=${person.hello:mm} 

5. Profile

Profile是Spring對不同環境提供不同配置功能的支持,可以通過激活、 指定參數等方式快速切換環境 (配置)

5.1 多profile文件

  • xml方式
    可以創建多個配置文件,文件命名格式是:application-{profile}.properties,默認使用的是application.properties的配置
    比如,我們可以創建application-test.properties、application-dev.properties、application-prod.properties,這三個文件分別在測試、開發、生產的環境中使用。

  • yml方式
    如果使用的是yml配置文件的話,可以使用yml的多文檔塊,yml文件中,使用---可以將yml分成多個文檔塊,默認使用的是最上面的第一個文檔塊,下面的根據---劃分爲2、3、4…文檔塊。

5.2 激活方式(指定配置文件)

  • 在配置文件中指定 spring.profiles.active=dev

xml文件方式,在application.properties文件中使用 spring.profiles.active=test激活指定的配置

yml文件

#激活指定profile的配置,springboot啓動的時候就會使用
server:
  port: 8081
spring: 
  profiles:
    active: prod
---
server:
  port: 8082
spring:
  profile: dev
---
server:
  port: 8083
spring:
  profiles: prod  #指定屬於哪個環境

  • 命令行:
    java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
    可以直接在測試的時候,配置傳入命令行參數

  • 虛擬機參數;
    -Dspring.profiles.active=dev

6. 配置文件加載位置

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

  • file:./config/ 項目根路徑下的config文件夾下
  • file:./ 項目根路徑下
  • classpath:/config/ 類路徑下(resource下)的config文件夾下
  • classpath:/ 類路徑下(resource下)
    以上是按照優先級從高到低的順序,SpringBoot啓動的時候,所有位置的配置文件都會被加載,高優先級中的配置會覆蓋低優先級中的配置,並且會形成互補配置,如果高優先級中沒有某項配置,而低優先級中有,就會使用低優先級的。

我們還可以通過spring.config.location來改變默認的配置文件位置
項目打包好以後,我們可以使用命令行參數的形式,啓動項目的時候來指定配置文件的新位置,指定配置文件和默認加載的這些配置文件共同起作用形成互補配置;

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

7. 外部配置加載順序

SpringBoot也可以從以下位置加載配置; 優先級從高到低;高優先級的配置覆蓋低優先級的配置,所有的配置會 形成互補配置

  1. 命令行參數
    所有的配置都可以在命令行上進行指定
    java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc多個配置用空格分開; --配置項=值
  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)配置文件
    (6、7、8、9總結就是由jar包外向jar包內進行尋找; 優先加載帶profile,再來加載不帶profile )
  10. @Configuration註解類上的@PropertySource
  11. 通過SpringApplication.setDefaultProperties指定的默認屬性

所有支持的配置加載來源,可以看官方文檔

8. 自動配置原理

配置文件中可以寫什麼配置,怎麼寫?
我們可以查看官方文檔配置文件能配置的屬性參照

springboot啓動的時候加載了主配置類,並開啓了自動配置功能@EnableAutoConfiguration。

@SpringBootApplication
    @EnableAutoConfiguration

@EnableAutoConfiguration的作用:

  • 使用@Import({AutoConfigurationImportSelector.class})給容器中導入了一些組件。
  • AutoConfigurationImportSelector類中的importSelector()方法中,調用了getAutoConfigurationEntry方法

    selectImports方法中調用了getAutoConfigurationEntry方法,這個方法又調用了getCandidateConfigurations方法

  • getAutoConfigurationEntry方法中
//獲取候選配置
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
  • getCandidateConfigurations方法中,調用了SpringFactoriesLoader.loadFactoryNames()方法,掃描所有jar包類路徑下 META-INF/spring.factories的文件,把掃描到的這些文件的內容包裝成properties對象,從properties中獲取到EnableAutoConfiguration.class(類名)對應的值,然後把它們添加在容器中。
    在這裏插入圖片描述

  • 每一個這樣的 xxxAutoConfiguration類都是容器中的一個組件,都加入到容器中,用他們來做自動配置

  • 每一個自動配置類都能進行自動配置功能,有了自動配置類,免去了我們手動編寫配置注入功能組件等的工作

以HttpEncodingAutoConfiguration(Http編碼自動配置)爲例解釋自動配置原理

@Configuration( //表示這是一個配置類
    proxyBeanMethods = false
)
/**
 * 啓動指定類的ConfigurationProperties功能;
 * 將配置文件中對應的值和 ServerProperties這個類綁定起來;
 * 並把 ServerProperties加入到ioc容器中
 */
@EnableConfigurationProperties({ServerProperties.class})
/**
 * 使用Spring底層@Conditional註解
 * 根據不同的條件進行判斷,如果滿足指定的條件,整個配置類裏面的配置就會生效;
 * 判斷當前應用是否是web應用,如果是,當前配置類生效
 */
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
//判斷當前項目有沒有這個類,CharacterEncodingFilter,SpringMVC中進行亂碼解決的過濾器
@ConditionalOnClass({CharacterEncodingFilter.class})
/**
 * 判斷配置文件中是否存在某個配置  server.servlet.encoding.enabled;如果不存在,判斷也是成立的
 * 即使我們配置文件中不配置server.servlet.encoding.enabled=true,也是默認生效的;
 */
@ConditionalOnProperty(
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
	//和springBoot中的配置文件綁定,和編碼相關的配置都在Encoding這個類中
	private final Encoding properties;
	
	//只有一個有參構造器的情況下,參數默認從容器中獲取
    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }
    
    @Bean  //給容器中添加一個組件,這個組件的某些值需要從properties中獲取
    @ConditionalOnMissingBean  //判斷容器有沒有這個組件?(容器中沒有才會添加這個組件)
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
    }
  1. 根據當前不同的條件判斷,決定這個配置類是否生效
  2. 一但這個配置類生效;這個配置類就會給容器中添加各種組件;這些組件的屬性是從對應的properties類中獲取的,這些類裏面的每一個屬性又是和配置文件綁定的;

所有在配置文件中能配置的屬性都是在xxxxProperties類中封裝着;配置文件能配置什麼就可以參照某個功能對應的這個屬性類

//從配置文件中獲取指定的值和這個類中的屬性進行綁定
@ConfigurationProperties(
    prefix = "server",
    ignoreUnknownFields = true
)
public class ServerProperties {
    private Integer port;
    private InetAddress address;

總結:

  • SpringBoot啓動會加載大量的自動配置類
  • 我們看我們需要的功能有沒有SpringBoot默認寫好的自動配置類
  • 再來看這個自動配置類中到底配置了哪些組件;(只要我們要用的組件有,我們就不需要再來配置了)
  • 給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。我們就可以在配置文件中指定這些屬性的值

xxxxAutoConfigurartion:自動配置類;

xxxxProperties:封裝配置文件中相關屬性,裏面又封裝了一些對象,屬性也可能在對象裏

9. @Conditional的擴展註解

springBoot啓動的時候,並不是把所有的自動配置類都加載到容器,必須是@Conditional指定的條件成立,纔給容器中添加組件,配置類裏面的所有內容才生效,這些條件就是基於spring底層的@Conditional註解實現的,springboot對這個註解進行了擴展。

@Conditional擴展註解 作用(判斷是否滿足當前條件)
@ConditionalOnJava 系統的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean
@ConditionalOnMissingBean 容器中不存在指定Bean
@ConditionalOnExpression 滿足SpEL表達式指定
@ConditionalOnClass 系統中有指定的類
@ConditionalOnMissingClass 系統中沒有指定的類
@ConditionalOnSingleCandidate 容器中只有一個指定的Bean,或者這個Bean是首選Bean
@ConditionalOnProperty 系統中指定的屬性是否有指定的值
@ConditionalOnResource 類路徑下是否存在指定資源文件
@ConditionalOnWebApplication 當前是web環境
@ConditionalOnNotWebApplication 當前不是web環境
@ConditionalOnJndi JNDI存在指定項

可以通過啓用 debug=true屬性;來讓控制檯打印自動配置報告,這樣我們就可以很方便的知道哪些自動配置 類生效。

參考
SpringBoot權威教程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章