springboot使用一個全局配置文件,配置文件名是固定的:html
配置文件的做用:修改springboot自動配置的默認值。springboot在底層都給咱們自動配置好了;java
配置文件位於src/resources下面。web
yaml a markup language 是一個標記語言,以數據爲中心,比其餘類型的標記語言更適合做爲配置文件。 標記語言:之前的配置文件大多都使用XXX.xml文件,spring
YAML:shell
server: port: 8081
XML:json
<server> <port>8081</port> </server>
properties:tomcat
server.port = 8081
person: lastName: zhaoyi list: - list1 - list2 maps: k1: v1 k2: v2 age: 25 boss: false dog: name: xiaohuang age: 30
// person類 @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private List<Object> list; private Map<String, Object> maps; private Integer age; private Boolean boss; private Dog dog; @Override public String toString() { return "Person{" + "lastName='" + lastName + '\'' + ", list=" + list + ", maps=" + maps + ", age=" + age + ", boss=" + boss + ", dog=" + dog + '}'; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public List<Object> getList() { return list; } public void setList(List<Object> list) { this.list = list; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getBoss() { return boss; } public void setBoss(Boolean boss) { this.boss = boss; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } } // dog類 package com.zhaoyi.hello1.com.zhaoyi.hello1.bean; public class Dog { private String name; private int age; @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
導入配置文件處理器,這樣就會有提示編寫資源的信息;springboot
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
只有組件是容器中的組件,才能使用ConfigurationProperties提供的功能;app
springboot單元測試:能夠在測試期間很方便的相似編碼同樣進行自動注入等容器功能;dom
@RunWith(SpringRunner.class) @SpringBootTest public class Hello1ApplicationTests { @Autowired Person person; @Test public void contextLoads() { System.out.println(person); } }
註釋掉application.yml的配置文件信息,新建一個application.properties文件,寫入和applicatio.yml相同功能的配置
person.age=14 person.last-name=張三 person.boss=false person.maps.k1=v1 person.maps.k2=v2 person.list=a,b,c person.dog.name=小狗 person.dog.age=5
運行測試後發現有關中文部分的輸出是亂碼。
idea使用的是utf-8編碼,在setting處查詢file encoding,設置爲utf-8,並選擇在運行時轉化爲ascll(勾選)
Spring中配置一個Bean:
<bean class="person"> <property name="lastName" value="zhangsan"></property> </bean>
其中,value能夠:
#{SPEL}
而@Value其實效果和其同樣,好比,在類屬性上寫
@Value("person.lastName") private String lastName @Value("#{11*2}") private Integer age
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的屬性 | 一個個指定 |
支持鬆散綁定 | 不支持鬆散綁定 | |
SpEL | 不支持 | 支持 |
JSR303數據校驗 | 支持 | 不支持 |
複雜類型封裝 | 支持 | 不支持 |
注: |
從上面的說明咱們能夠知道,二者在配置上基本能夠相互替換,彼此功能也大致一致,那麼,咱們在業務場景中,該選用哪種進行編碼呢?
@Value
.@RestController public class HelloController { @Value("${person.last-name}") private String name; @RequestMapping("/") public String hello(){ return "hello world, " + name; } }
@ConfigurationProperties
;
@PropertySource
加載指定的配置文件。
咱們知道,@ConfigurationProperties默認從全局配置文件(application.properties)中獲取值,但一般咱們會將相關的配置文件放到某個配置文件中,例如,咱們將有關person的配置信息放到person.properties中去。爲了使組件類Person可以找到配置文件的配置信息,須要使用增長新的註解@PropertySource
指定從哪裏加載配置等相關信息。
@PropertySource("classpath:person.properties") @Component @ConfigurationProperties(prefix = "person") public class Person { }
@ImportResource
導入Spring的配置文件,讓配置文件裏面的內容生效。
package com.zhaoyi.hello1.service; public class HelloService { }
<?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.zhaoyi.hello1.service.HelloService"></bean> </beans>
那麼問題來了,在spring-boot中顯然是不會加載此bean的,咱們測試一下。
@RunWith(SpringRunner.class) @SpringBootTest public class Hello1ApplicationTests { @Autowired ApplicationContext ioc; @Test public void testBean(){ System.out.println("Is have helloService bean? " + ioc.containsBean("helloService")); } }
測試結果:
Is have helloService bean? false
Spring boot裏面是沒有Spring的配置文件,咱們本身編寫的配置文件,也不能自動識別,想讓Spring的配置文件生效,則須要手動指示將其加載進行,使用@ImportResource
標註在一個配置類(例如應用程序啓動類,他也是一個配置類)上:
@ImportResource(locations = {"classpath:bean.xml"}) @SpringBootApplication public class Hello1Application { public static void main(String[] args) { SpringApplication.run(Hello1Application.class, args); } }
這時候運行測試用例就會發現,bean已經出如今容器中了。
@ImportResource(locations = {"classpath:bean.xml"})
通常咱們不會使用6中所提到的這種方式,由於xml配置方式實在是寫了太多的無用代碼,若是xml的標籤聲明,以及頭部的域名空間致使。所以,SpringBoot推薦給容器中添加組件的方式:全註解方式。也就是用配置類來充當bean配置文件。以下,即爲一個配置類:
/** * @Configuration 指明當前類是一個配置類 */ @Configuration public class MyConfig { // 將方法的返回值添加到容器中:容器中這個組件的id就是方法名 @Bean public HelloService helloService(){ return new HelloService(); } }
經過該配置類,能夠爲容器中添加了一個名爲helloService
的bean。
不管是使用yaml仍是properties都自持文件佔位符配置方式
${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int[1024,65536]}
person.age=14 person.last-name=張三${random.uuid} person.boss=false person.maps.k1={person.xxx:novalue} person.maps.k2=v2 person.list=a,b,c person.dog.name=${person.last-name}_小狗狗 person.dog.age=${random.int}
Person{lastName='張三1b9fbbb1-6c58-4a35-8165-ad23800d7456', list=[a, b, c], maps={k2=v2, k1=novalue}, age=14, boss=false, dog=Dog{name='張三b3a355d7-54ce-4afd-9ae6-d3be4aeb4165_小狗狗', age=-122850975}}
注意:留意默認值那一項設置,咱們如願的成功設置了默認值novalue。在實際項目中,這種狀況比較經常使用,稍微留意一下。若是沒有默認值,則會將${xxx}這一段做爲值,這顯然是錯誤的。
profile通常是spring用來作多環境支持的,能夠經過激活指定參數等方式快速的切換當前環境。
咱們在主配置文件編寫的時候,文件名能夠是 application-{profile}.properties(yml)
例如: application-dev.properties、application-prod.properties等。
spring.profiles.active=dev
--spring.profiles.active=dev
edit configuration
,在environment配置節中的Program arguments
寫入spring.profiles.active=dev便可。java -jar your-jar-name.jar --spring.profiles.active=dev
便可。Program arguments
上一項即爲虛擬機參數激活,不過填寫的內容爲-Dspring.profiles.active=dev
,即多了一個-D
而已。若咱們使用properties,則須要編寫多個不一樣的配置文件,但若是咱們使用yml的話,則能夠經過多文檔配置節實現單文件管理。注:有關yml相關的知識參考此文檔的前半部分。
能夠看到,咱們經過---
三個橫線實現文檔分割,同時在每個文檔塊處指定了各個profile的不一樣配置信息,即dev環境下啓動服務使用8082端口,prod環境下使用8083端口。而指定哪個profile則是經過默認的文檔塊(即第一塊)中的spring.profiles.active進行配置。完成如上配置以後咱們啓動服務,顯然此時是以激活的prod環境所配置的端口8083運行的,以下啓動日誌所示:
com.zhaoyi.hello1.Hello1Application : The following profiles are active: prod o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8083 (http)
也就說,當咱們選定一個profile後,對應的文檔塊的配置就會所有生效。
SpringBoot啓動會掃描如下位置的application.properties或者application.yml文件做爲SpringBoot的默認配置文件:
以上是按照優先級順序從高到低,全部位置的文件都會被加載,但對於相同配置:高優先級配置內容會覆蓋低優先級配置的內容,其餘的則互補。
咱們也能夠經過spring.config.location參數來設置默認的配置文件位置。項目打包好之後,使用命令行參數形式來指定配置文件的新位置,指定的配置文件和默認加載的配置互補起做用。而且咱們指定的該配置文件優先級是最高的。
SpringBoot支持多種外部配置方式,他能夠從如下位置加載配置,按優先級從高到低排列以下(高優先級配置覆蓋低優先級配置,全部配置會造成互補配置):
java -jar package_name_version.jar --server-port=8080 --server.context-path=/hello
多個參數之間用空格分開,用--parameter_name=value
進行配置。
都是由jar包外向jar包內進行尋找,高優先級的配置覆蓋低優先級的配置。而後 優先加載帶profile的:
在jar文件的同級目錄放一個application.properties文件,其配置內容會被加載;
再來加載不帶profile的:
官方文檔列出了比這裏更多的配置文檔,請參考,版本更迭地址會常常變更,可自行前往官方網站進行查看。
配置文件的配置屬性能夠參照官方文檔:前往
@EnableAutoConfiguration
。public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
掃描全部jar包類路徑下META-INF/spring.factories
文件,吧掃描到的這些文件的內容包裝成properties對象;從properties中獲取到EnableAutoConfiguration.class類對應的值,而後把他們添加在容器中;
說到底,就是將類路徑下META-INF/spring.factories
裏面配置的全部EnableAutoConfiguration的值加入到了容器中。
# Auto Configure 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.CloudServiceConnectorsAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ ...(more)
每個這樣的xxxAutoConfiguration類都會是容器中的一個組件,都加入到了容器中,用他們來作自動配置。
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
爲例:@Configuration @EnableConfigurationProperties({HttpProperties.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty( prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration { @Bean @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE)); return filter; } ... }
咱們能夠看到該類的註解以下:
@Configuration
毫無疑問,代表這是一個配置類,和咱們要自定義一個配置文件同樣,實現給容器中添加組件;@EnableConfigurationProperties
啓動指定類的ConfigurationPropertiesg功能,這樣就能夠將配置文件中對應的值和HttpEncodingProperties綁定起來;並把HttpEncodingProperties加入到ioc容器中;@ConditionalOnWebApplication
Spring底層@Conditional
註解,根據不一樣的條件,若是知足指定的條件,整個配置類裏面的配置就會生效;此處判斷的就是當前應用是否是Web應用;不然配置不生效;@ConditionalOnClass
判斷當前項目有沒有類(CharacterEncodingFilter
),這是SpringMVC中進行亂碼解決的過濾器;@ConditionalOnProperty
判斷配置文件中是否存在某個配置 spring.http.encoding.enabled
;若是不存在,則判斷成立,若是沒有配置,則此處將其設置爲true
;@Bean
給容器中添加Bean組件,該組件的某些值須要從properties中獲取,此處即爲HttpEncodingProperies,顯然此刻他的取值已經和springboot的properties文件進行注入了;根據不一樣的條件進行判斷當前這個配置類是否生效。一單這個配置類生效,這個配置類就會給容器中添加各類組件;這些組件的屬性均來自於其對應的Properties類的,這些Properties類裏面的每個屬性,又是和配置文件綁定的。
@EnableConfigurationProperties
指定的properties類HttpProperties
:@ConfigurationProperties( prefix = "spring.http" ) public class HttpProperties {
xxxAutoConfiguration 這種類就是用來作自動配置的,他會給容器中添加相關的組件,其對應的Properties則對應了配置的各類屬性;也就是說,經過這些配置類,咱們之前須要在SpringMVC中寫配置類、文件實現的東西,如今,只須要在Properites配置文件中加入相關的配置便可,再也不那麼麻煩了。
固然,一些特殊的配置仍是得本身寫組件的哦。
只有其指定的條件成立,配置類的全部類型纔會生效,更小範圍的,例如註釋在某個Bean組件上面的相關條件註解成立,纔會生成該Bean。
@Conditional擴展註解 | 做用(判斷是否知足當前指定條件) |
---|---|
@ConditionalOnJava | 系統的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 知足SpEL表達式指定 |
@ConditionalOnClass | 系統中有指定的類 |
@ConditionalOnMissingClass | 系統中沒有指定的類 |
@ConditionalOnSingleCandidate | 容器中只有一個指定的Bean,或者這個Bean是首選Bean |
@ConditionalOnProperty | 系統中指定的屬性是否有指定的值 |
@ConditionalOnResource | 類路徑下是否存在指定資源文件 |
@ConditionalOnWebApplication | 當前是web環境 |
@ConditionalOnNotWebApplication | 當前不是web環境 |
@ConditionalOnJndi | JNDI存在指定項 |
咱們能夠發現,儘管咱們擁有許多的自動配置類,其仍是得必須知足必定條件纔會生效,該機制就是有@Conditinal派生註解等控制的,常見的是
@ConditionalOnClass
,即判斷當前系統具不具有相關的類。
配置文件application.properties中添加配置,開啓Debug模式:
debug=true
默認狀況下debug的值爲false,經過啓用debug=true
屬性,讓控制檯打印相關的報告,例如那些自動配置類啓用(positive matches)、沒啓用(negative matches)等。