SpringBoot 配置及原理
一、Spring Boot全域性配置檔案:1)、application.properties名稱固定。2)、application.yml 配置檔案。兩個檔案的作用:可以覆蓋SpringBoot配置的預設值。
◀ YAML(is not a Markup Language:不僅僅是一個標記語言):以前的配置檔案,大多是xx.xml檔案,而YAML是以資料為中心,比json、xml等更適合做配置檔案。
#普通配置檔案.properties的語法 #server.port=80 #XML的寫法 #<server> # <port>8080<port/> #<server/> #yml 以資料為中心的語法 server: port: 8080
◀ YML語法:基本語法:k:(空格)v--->表示一對鍵值對。(以空格縮排來控制層級關係;只要是左對齊的一列資料,都是同一層級)屬性和值也是大小寫敏感。
server:
port: 8080
path: /hello
spring:
profiles: dev
◀ 值得寫法:1)字面量:普通的值(數字、字串、布林),字串預設是不用加上單引號或者雙引號,但也可以加,但是有區別:雙引號,不會轉義字串裡面的特殊字元,特殊字元會作為本身想表達的意思。單引號,會轉義特殊字元,特殊字元最終只是一個普通的字串資料。
2)、物件(屬性和值)或者Map(鍵值對)的表達—>k: v形式,物件還是k: v的方式。比較抽象,我們舉個栗子看看:
#yml正常寫法
friends:
lastName: zhangsan
age: 20
#行內寫法
friends: {lastName: zhangsan,age: 20}
3)、陣列(List、Set)用 ‘- 值’ 表示陣列中的一個元素,也舉一個栗子:
# yml正常寫法 -值 形式
pets:
- cat
- dog
#行內寫法
pets: [cat,dog]
◀ 配置檔案注入:測試上面資料賦值是否正確。
1)、準備配置檔案:application.yml
person:
lastName: zhangsan
age: 20
boss: false
birth: 2018/8/20
map: {k1: v1,k2: v2}
lists: [listi,zhaoliu]
dog:
name: gou
age: 2
2)、準備JavaBean:@ConfigurationProperties(prefix ="person")表示將配置檔案中的person的每一個屬性對映到這個元件中,但只有這個元件是容器中的元件,才能提供功能。需要使用@Component標註才能成為容器元件。
@Component
@ConfigurationProperties(prefix ="person")
public class Person {
private String lastName;
private Integer age;
private boolean boss;
private Date birth;
private Map<String,String> map;
private List lists;
private Dog dog;
}
3)、優化:當準備2中的檔案,會提示我們“Spring Boot Configuration Annotation ...”點選去後會發現如下starters資訊,那麼我們將此配置於pom檔案中,作用:當我們在配置檔案中,給帶有@ConfigurationProperties的實體類賦值時會有屬性提示。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
4)、測試: 進入test目錄底下的類目錄,直接匯入person輸入,檢視是否已賦值即可。
//使用Spring的驅動器,不用再使用JUnit的驅動器了
@RunWith(SpringRunner.class)
@SpringBootTest
public class HellowordQuickStartApplicationTests {
//在測試期間可以類似編碼一樣進行自動注入
@Autowired
Person person;
@Test
public void testPersion(){
System.out.println(person);
}
}
5)、properties中的語句與yml不同,以下是properties的配置語句。
#person.lastName=張三 也是可以的
person.last-name=張三
person.age=18
person.birth=2013/04/23
person.boss=false
person.map.key1=v1
person.map.key2=v2
person.lists=a,b,c
person.dog.name=dog
person.dog.age=2
6)、測試的時候可能會出現亂碼,設定如下。properties預設的編碼時ASK碼,我們需要將其設定為UTF-8來解決亂碼問題。
7)、第二種賦值方式:@ Value(“字面量/${key}從環境變數、配置檔案中獲取值/#{SpEL}”)---三種傳值方式
@Component
//@ConfigurationProperties(prefix ="person")
public class Person {
//@email @Value不支援校驗(JSR303資料校驗)
@Value("${person.last-name}")
private String lastName;
//SPEL
@Value("#{22*3}")
private Integer age;
@Value("true")
private boolean boss;
● @Vaule與@ConfigurationProperties兩者的區別如下:(其實@Value最多用在獲取單個值的時候使用)
@configuration | @value | |
功能 | 批量注入配置檔案中的屬性 | 每個屬性單獨配置 |
鬆散繫結(鬆散語法) | 支援(大小寫不敏感) | 不支援(與配置檔案保持一致) |
SpEL | 不支援(不能用於邏輯計算) | 支援#{邏輯計算} |
JSR303資料校驗 | 支援@validated | 不支援 |
複雜型別封裝 | 支援 | 不支援(map物件) |
二、@PropertySource與@ConfigurationProperties之間的區別:@ConfigurationProperties:預設從全域性配置檔案中載入值。
● @PropertySource:指向自己定義的properties配置檔案,新建person.properties配置檔案(省略),如下獲取值。
//優先順序高於@ConfigurationProperties(prefix ="person")
@PropertySource(value = {"classpath:person.properties"})
@Component
//@ConfigurationProperties(prefix ="person")
//@Validated
public class Person {
● @ImportResource:匯入Spring的配置檔案,讓配置檔案裡面的內容生效 。
1)、定義配置檔案bean.xml(以前的配置,SpringBoot不這麼用)
<?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.atguigu.Servers.HelloService"></bean>
</beans>
2)、在主程式中使用@ImportResource註解匯入bean.xml配置檔案
@ImportResource(locations={"classpath:bean.xml"})
@SpringBootApplication
public class HellowordQuickStartApplication {
● SpringBoot中(配置類====配置檔案xml)推薦使用配置類,如下建立:
//@Configuration指明當前類是一個配置類 替代配置檔案
@Configuration
public class MyAppConfig {
//@bean註解就相當於<bean></bean>標籤
@Bean
//方法名就相當於xml中的id , 專案啟動時就會將元件加入容器中
public HelloService helloService(){
System.out.println("@Bean給容器中新增元件");
return new HelloService();
}
}
三、配置檔案佔位符
1)、隨機數(瞭解即期)
${random.value}、${random.int}、${random.log}、${random.int(10)}
2)、佔位符(當屬性不存在時,可以給一個預設值,例如下面age屬性值得獲取)
persion.last-name=張三
persion.dog.name=${persion.last_name}_dog
perdion.dog.age=${persion.noexistage:20}
四、Profile:是Spring對不同環境提供不同配置功能的支援,可以通過啟用、指定引數等方式快速切換環境:
1)、多profile檔案形式(瞭解一下,我們使用更多的是2中的yml形式):
我們可以編寫多個配置檔案,對應多個場景(開發、測試、生產等),檔名可以是application-{profile}.properties/yml的形式命名,例如:application-dev.properties
專案啟動時預設使用application.properties的配置,如果要啟用開發配置檔案,在application.properties中輸入如下啟用資訊。
#啟用dev開發模式的配置檔案,就不用application.properties檔案的配置了
spring.profiles.active=dev
2)、yml支援多文件塊方式(推薦使用):通過“---”來劃分文件塊,Document表示所處模組的位置/總塊 。
# --- 稱為多文件快 , 簡寫1中的形式
---
server:
port: 8080
path: /hello
# 如下為啟用profiles ,如果不啟用則預設為Document1中的配置
spring:
profiles:
active: dev
---
server:
port: 8084
spring:
profiles: prod
---
server:
port: 8081
spring:
profiles:
active: dev
3)、啟用指定profile方式,上面用的都是第一種:
(1)、在預設配置application.properties中設定spring.profiles.active屬性
spring.profiles.active=dev
(2)、命令列:--spring.profiles.active=dev
命令列執行jar包的方式:java -jar xxx.jar --spring.profiles.active=dev;
(3)、虛擬機器引數:-Dspring.profiles.active=prod;
五、配置檔案載入位置:也就優先順序
SpringBoot啟動會掃描一下位置的application.properties或者application.yml檔案作為SpringBoot的預設配置檔案
(1)、file:./config/ (專案底下的config目錄)
(2)、file:./ (直接位於專案底下的配置檔案)
(3)、classpath:/config/ (config檔案預設沒生成,需要自己建立)
(4)、classpath:/ (專案建立後,配置檔案預設位置)
以上是按照優先順序從高到低的順序,所有位置的檔案都會被載入,高優先順序配置內容會覆蓋低優先順序配置的相同內容。
我們也可以通過spring.config.location來改變預設配置(專案打包成功以後,我們可以使用命令列引數的形式,啟動專案來指定配置檔案的新位置;指定的配置檔案會共同起作用,形成互補作用),這個優先順序肯定最高了。而且我們要知道,打jar包的時候只包含src底下的main和resource檔案,1、2中的不會被打包進去。其實將jar包與配置檔案*.yml等放在同一個目錄下的情況也比較多常見,因為靈活。專案啟動時可以自動載入同目錄下的*.yml等配置檔案。且優先順序高於內部的配置檔案,之間互補配置。
#命令列新增配置,優先順序最高
java -jar xxx.jar --spring.config.location=d:\xxx.properties
六、自動配置原理:
【1】、SpringBoot啟動的時候載入主配置類,@SpringBootApplication下開啟了主配置功能@EnableAutoConfiguration
【2】、@EnableAutoConfiguration作用:1)、利用EnableAutoConfigurationImportSelector給容器匯入一些元件。
2)、可以檢視selectImports()方法的內容:
List configurations = getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置。
SpringFactoriesLoader.loadFactoryNames()掃描所有jar包類路徑下 META‐INF/spring.factories把掃描到的這些檔案的內容包裝成properties物件從properties中獲取到EnableAutoConfiguration.class類(類名)對應的值,然後把他們新增在容器中
【3】、將 類路徑下 META-INF/spring.factories 裡面配置的所有EnableAutoConfiguration的值加入到了容器中;
# EnableAutoConfiguration 對應 @EnableAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
每一個這樣的 xxxAutoConfiguration類都是容器中的一個元件,都加入到容器中;用他們來做自動配置;
【4】、每一個自動配置類進行自動配置功能,以HttpEncodingAutoConfiguration(Http編碼自動配置)為例解釋自動配置原理;
@Configuration //表示這是一個配置類,以前編寫的配置檔案一樣,也可以給容器中新增元件
@EnableConfigurationProperties(HttpEncodingProperties.class) //啟動指定類的
ConfigurationProperties功能;將配置檔案中對應的值和HttpEncodingProperties繫結起來;並把
HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication //Spring底層@Conditional註解(Spring註解版),根據不同的條件,如果
//滿足指定的條件,整個配置類裡面的配置就會生效; 判斷當前應用是否是web應用,如果是,當前配置類生效
@ConditionalOnClass(CharacterEncodingFilter.class) //判斷當前專案有沒有這個類
CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing =
true) //判斷配置檔案中是否存在某個配置 spring.http.encoding.enabled;如果不存在,判斷也是成立的
//即使我們配置檔案中不配置pring.http.encoding.enabled=true,也是預設生效的;
public class HttpEncodingAutoConfiguration {
//他已經和SpringBoot的配置檔案映射了
private final HttpEncodingProperties properties;
//只有一個有參構造器的情況下,引數的值就會從容器中拿
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean //給容器中新增一個元件,這個元件的某些值需要從properties中獲取
@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;
}
根據當前不同的條件判斷,決定這個配置類是否生效?一但這個配置類生效;這個配置類就會給容器中新增各種元件;這些元件的屬性是從對應的properties類中獲取的,這些類裡面的每一個屬性又是和配置檔案繫結的;
【5】、所有在配置檔案中能配置的屬性都是在xxxxProperties類中封裝者;配置檔案能配置什麼就可以參照某個功能對應的這個屬性類
@ConfigurationProperties(prefix = "spring.http.encoding") //從配置檔案中獲取指定的值和bean的屬
性進行繫結
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF‐8");
精髓:1)、SpringBoot啟動會載入大量的自動配置類
2)、我們看我們需要的功能有沒有SpringBoot預設寫好的自動配置類;
3)、我們再來看這個自動配置類中到底配置了哪些元件;(只要我們要用的元件有,我們就不需要再來配置了)
4)、給容器中自動配置類新增元件的時候,會從properties類中獲取某些屬性。我們就可以在配置檔案中指定這些屬性的值;
xxxxAutoConfigurartion:自動配置類,給容器中新增元件。
xxxxProperties:封裝配置檔案中相關屬性;
七、@ConditionalOnxxx中的@Conditional派生註解(Spring註解版原生的@Conditional作用)作用:必須是@Conditional指定的條件成立,才給容器中新增元件,配置配裡面的所有內容才生效。
● 自動配置類必須在一定的條件下才能生效,那麼我們如何知道哪些配置類生效哪些沒有生效,其實我們可以通過在配置檔案啟用 debug=true屬性,就可以檢視哪些配置類生效。
debug=true
▶ 通過控制檯列印自動配置報告,我們就可以知道哪些自動配置類生效(Positive matches:匹配成功的自動配置類)
Positive matches:
-----------------
CodecsAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
CodecsAutoConfiguration.JacksonCodecConfiguration matched:
- @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
CodecsAutoConfiguration.JacksonCodecConfiguration#jacksonCodecCustomizer matched:
- @ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found bean 'jacksonObjectMapper' (OnBeanCondition)
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- found ConfigurableWebEnvironment (OnWebApplicationCondition)
▶ 自動配置未生效類(Negative matches:匹配失敗的自動配置類)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice', 'org.aspectj.weaver.AnnotatedElement' (OnClassCondition)
ArtemisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory' (OnClassCondition)