1. SpringBoot配置文件存放位置以及讀取順序
默認情況下,我們可以將application.properties或者application.yaml(為了方便演示,本文以下均以application.properties介紹)放置在如下四處:
1.1、idea中,為了我們本地方便開發測試,我們在此處創建一個config目錄,然後把application.properties放進去,項目正常運行。
jar包會自動生成在target目錄下。
我們將生成的jar包,復制出來,到另外文件夾進行運行,比如,我現在該jar包復制到test目錄下,但是這個時候是起不來,因為沒有配置文件,雖然我們在idea裡面是有config目錄的,但是它並不沒有被打包進去。我們要把config目錄也復制過來,跟該jar包放在同一個目錄下。
在此處,我們可以使用java -jar demo-0.01-SNAPSHOT來運行項目。
正常運行。
當我們將其打成jar包時,application.properties同樣不會被打包進jar包中。需要另外復制出來和jar包放在才能正常運行。
推薦以上兩種方式來放置配置文件,如果不寫開發,測試,和生產好幾套環境配置文件的話,就可以直接打開配置文件,改成自己需要的配置即可。
以下兩種方式是將該配置文件打包在jar包裡面了,即便只改一個埠號,開發人員先改配置文件,再打包,再運行。此處也記錄下,並解開jar包,看下該配置文件被打包後,放置的位置。
打包後,如下圖,jar包再target裡面,我們尋找下application.properties文件。為了方便演示,我們將target目錄下的demo-0.0.1-SNAPSHOT.jar放到一個新目錄給它解壓開,找下該配置文件,我放置到了一個test目錄下。
解壓後:如下圖,我們進入目錄
發現config目錄被放置在classes目錄下。然後這也就讓我們明白了,什麼是classpath?classpath的路徑到底指的是哪裡,在idea中我們就把它放置在resource目錄,該目錄就是表示classpath。而被打成jar包後classes目錄就是所謂的classpath。
所有的yaml文件,同理。
2. springboot載入properties和yml配置文件的順序
假設一個項目在同一位置同時存帶讓在application.properties和application.yml文件,
且其中都含有相同的某個key,但value不同,如:山行伏
application.properties中:server.port=8001,
application.yml中:server.port=8888。
問題:springboot是否都載入這兩個配置文件?如果兩個文件有相同的key,取哪一個文件的value?
答: 都載入,且按properties→yml的順序載入。
在看到spring.factories中,配置載入器順序是先執行再到YamlPropertySourceLoader。
在ConfigFileApplicationListener獲取server.port這個key的value時候,可以發現兩配置文件全都載入進去了,且注意順序,application.properties文件在前。
getSource()方法獲取到兩個Source,先從application.properties文件中查找值,一旦找到立逗攜即返回,如果找不到再從application.yml中查找。
3. Spring Boot 第二彈,配置文件詳解-史上最全
Spring Boot 官方 提供了兩種常用的配置文件格式,分別是 properties 、 YML 格式。相比於 properties 來說, YML 更加年輕,層級也是更加分明。 強烈推薦使用 YML 格式
Spring Boot項目 啟動會掃描以下位置的 application.properties 或者 application.yml 作為默認的配置文件.
徒手撕源碼
內部類Loader的load方法
getSearchLocations()方法
asResolvedSet()
下面給出優先順序 從高到低 的配置文件排列順序:
以設置應用埠為例 初體驗Spring Boot配置文件
properties後綴結尾(application.properties)
yml/yaml後綴結尾(application.yml/application.yaml)
數字,字元串,布爾,日期
對象、Map
數組
數字,字元串,布爾,日期
對象、Map
數組
@ConfigurationProperties(prefix = "person")詳解
標注在類上
標注在方法上
綜上所述
@ConfigurationProperties 註解能夠輕松的讓配置文件跟實體類綁定在一起。
值得關注的是: @ConfigurationProperties 這個註解僅僅是支持從 Spring Boot的默認配置文件 中取值,也就是 application.properties 、 application.yml 、 application.yaml ,那我們如何從自定義配置文件取值呢???
別著急,有解決辦法,那就是再加一個註解: @PropertySource(value = "classpath:custom-profile.properties") ,下面會有對 @PropertySource 註解的介紹。請耐心往下面看。
使用@PropertySource註解
對應配置文件
創建兩個配置文件 custom-profile.yml、custom-profile1.yml ,如下去引入。
我們可以通過控制變數法進行測試,具體過程我這里就不贅述了。
直接說 結論 吧: Spring載入順序 為 從左到右順序載入 ,後載入的會 覆蓋 先載入的屬性值。
另外需要注意的是 : @PropertySource 默認載入 xxx.properties類型 的配置文件,不能載入 YML格式 的配置文件。如何解決呢?下面來解決這一問題
對應配置文件:
編寫PropertiesController
擴展功能
application.yml 主配置文件
application-dev.yml 開發配置文件
application-prod.yml 生產配置文件
application-test.yml 測試配置文件
(1)主配置文件:配置激活選項
(2)其他配置文件:指定屬於哪個環境(同yml,只不過表現形式是 key=value 的,三個配置文件分別是: application-dev.properties , application-prod.properties , application-test.properties )
無論是使用上述 多文檔塊 的方式,還是新建 application-test.yml 文件,都可以在配置文件中指定 spring.profiles.active=test 激活指定的profile。
感謝閱讀小生文章。祝大家早日富可敵國,實現財富自由。
寫文不易 ,一定要 點贊、評論、收藏哦 , 感謝感謝感謝!!!
4. Spring載入多個配置文件載入順序是怎麼樣的
這個順序不需要關心吧?
Spring是先載入配置文件,然後更加姿巧配置文件再初始化相應的類
比如你在B配置文件中聲明了一個BeanA 在A配置文件中用到了這個BeanA,Spring 不會由於配置文件載入順跡穗鍵序的問題而造成找不到BeanA的錯族碰誤的。
5. spring常用註解
一、組件註解
1、 @Component(「xxx」)
指定某個類是容器的bean, @Component(value="xx") 相當於 ,其中 value 可以不寫。
用於標注類為spring容器bean的註解有四個, 主要用於區別不同的組件類,提高代碼的可讀性:
a、 @Component, 用於標注一個普通的bean
b、 @Controller 用於標注一個控制器類(控制層 controller)
c、 @Service 用於標注業務邏輯類(業務邏輯層 service)
d、 @Repository 用於標注DAO數據訪問類 (數據訪問層 )
對於上面四種註解的解析可能是相同的,盡量使用不同的註解提高代碼可讀性。
註解用於修飾類,當不寫value屬性值時,默認值為類名首字母小寫。
2、 @Scope(「prototype」)
該註解和 @Component 這一類註解聯合使用,用於標記該類的作用域,默認 singleton 。
也可以和 @Bean 一起使用,此時 @Scope 修飾一個方法。關於@Bean稍後有說明
3、 @Lazy(true)
指定bean是否延時初始化,相當於 ,默認false。@Lazy可以和@Component這一類註解聯合使用修飾類,也可以和@Bean一起使用修飾方法
注 :此處初始化不是指不執行 init-method ,而是不創建bean實例和依賴注入。只有當該bean(被@Lazy修飾的類或方法)被其他bean引用(可以是自動注入的方式)或者執行getBean方法獲取,才會真正的創建該bean實例,其實這也是BeanFactory的執行方式。
4、 @DepondsOn({「aa」,「bb」})
該註解也是配合 @Component 這類註解使用,用於強制初始化其他bean
上面的代碼指定,初始化bean 「userAction"之前需要先初始化「aa」和「bb」兩個bean,但是使用了@Lazy(true)所以spring容器初始化時不會初始化"userAction」 bean。
5、 @PostConstructor和@PreDestroy
@PostConstructor 和 @PreDestroy 這兩個註解是j2ee規范下的註解。這兩個註解用於修飾方法,spring用這兩個註解管理容器中spring生命周期行為。
a、 @PostConstructor 從名字可以看出構造器之後調用,相當於 。就是在依賴注入之後執行
b、 @PreDestroy 容器銷毀之前bean調用的方法,相當於
6、 @Resource(name=「xx」)
@Resource 可以修飾成員變數也可以修飾set方法。當修飾成員變數時可以不寫set方法,此時spring會直接使用j2ee規范的Field注入。
@Resource有兩個比較重要的屬性,name和type
a、 如果指定了name和type,則從Spring容器中找到唯一匹配的bean進行裝配,找不到則拋出異常;
b、 如果指定了name,則從spring容器查找名稱(id)匹配的bean進行裝配,找不到則拋出異常;
c、 如果指定了type,則從spring容器中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常;
d、 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配
如果沒有寫name屬性值時
a、 修飾成員變數,此時name為成員變數名稱
b、 修飾set方法,此時name 為set方法的去掉set後首字母小寫得到的字元串
7、 @Autowired(required=false)
@Autowired可以修飾構造器,成員變數,set方法,普通方法。@Autowired默認使用byType方式自動裝配。required標記該類型的bean是否是必須的,默認為必須存在(true)。
可以配合 @Qualifier(value="xx") ,實現按beanName注入:
a、 required=true(默認),為true時,從spring容器查找和指定類型匹配的bean,匹配不到或匹配多個則拋出異常
b、 使用 @Qualifier("xx") ,則會從spring容器匹配類型和 id 一致的bean,匹配不到則拋出異常
@Autowired會根據修飾的成員選取不同的類型:
a、 修飾成員變數。該類型為成員變數類型
b、 修飾方法,構造器。注入類型為參數的數據類型,當然可以有多個參數
8、demo
業務邏輯層:
數據訪問層:
測試類:
輸出結果:
可以看到雖然UserDao 使用@Lazy,但是還是在spring容器初始化的時候還是創建了UserDao實例。原因很簡單,因為在UserService中需要注入UserDao,所以在此時創建的UserDao實例也屬於延時初始化。
在上面我們還使用了兩個介面InitializingBean 和DisposableBean,這兩個介面用於管理 singleton 作用域的bean的生命周期,類似init-method和destroy-method。不同之處就是調用的循序不一致:
a、 初始化調用順序 :@PostConstructor > InitializingBean > init-method 用於指定bean依賴注入後的行為
b、 銷毀調用順序 @PreDestroy > DisposableBean > destroy-method 用於定製bean銷毀之前的行為
該註解是AspectJ中的註解,並不是spring提供的,所以還需要導入aspectjweaver.jar,aspectjrt.jar,除此之外還需要依賴aopalliance.jar
依賴包:
UserDao.java
配置文件 applicationContext.xml:
測試類:
1、 @Aspect
修飾Java類,指定該類為切面類。當spring容器檢測到某個bean被@Aspect修飾時,spring容器不會對該bean做增強處理(bean後處理器增強,代理增強)
2、 @Before
修飾方法,before增強處理。用於對目標方法(切入點表達式表示方法)執行前做增強處理。可以用於許可權檢查,登陸檢查。
常用屬性:
value: 指定切入點表達式 或者引用一個切入點
對com.example.aop 包下所有的類的所有方法做 before增強處理:
結果:
如果同一條切入點表達式被使用多次,可以使用更友好的方式。定義一個切入點:
增強方法可以接受一個JoinPoint 類型的參數,用於獲取被執行目標方法的一下屬性。
結果:
3、 @AfterReturning
修飾方法,afterreturning增強處理。目標方法正常結束後做增強處理。
常用屬性:
a、 pointcut/value:指定切入點表達式
b、 returning:指定一個參數名,用於接受目標方法正常結束時返回的值。參數名稱需要在增強方法中定義同名的參數。
注意:
a、 如果使用了returning 。那麼增強方法中的數據類型必須是返回結果的類型或者父類型,否則不會調用該增強處理。
b、 使用了returning 還可以用來 修改返回結果 。
以上面的例子來說,目標方法返回結果類型應該滿足下面的條件
修改返回值:
結果:
可以看到 AfterReturning 修改了返回結果。
4、 @AfterThrowing
修飾方法,afterthrowing增強處理。當目標程序方法拋出 異常或者異常無法捕獲時,做增強處理。
常用屬性:
a、 pointcut/value :指定切入點表達式
b、 throwing:指定一個形參,在增強方法中定義同名形參,用於訪問目標方法拋出的異常
參數類型必須是 Throwable 的子類,同樣也會有上面@AfterReturning 參數類型匹配的問題。
5、 @After
修飾方法 ,after增強處理。無論方法是否正常結束,都會調用該增強處理(@After= @AfterReturning+@AfterThrowing)。但是該增強方式無法獲取目標方法的返回結果,也獲取目標方法拋出的異常。所以一般用於進行釋放資源,功能類似於 finally。
常用屬性:
a、 value :指定切入點表達式
結果:
從上面的結果來看 After 增加處理 ,因為不能接受返回結果作為參數,所以不能修改返回結果。
6、 @Around
修飾方法, around增強處理。該處理可以目標方法執行之前和執行之後織入增強處理(@Before+@AfterReturning)。
Around增強處理通常需要在線程安全的環境下使用,如果@Before和@AfterReturning可以處理就沒必要使用@Around。
常用屬性:
a、 value :指定切入點表達式
當定義一個Aound增前處理時,增強方法第一形參需要時ProceedingJoinPoint類型。ProceedingJoinPoint有一個Object proceed()方法,用於執行目標方法。當然也可以為目標方法傳遞數組參數,來修改目前方法的傳入參數。
around小結:
a、 Around增強處理通常需要 在線程安全 的環境下使用
b、 調用 proceed()可以獲取返回結果,所以可以修改目標方法的返回值
c、 proceed(Object[] var1) 可以修改入參,修改目標方法的入參
d、 可以進行目標方法執行之前和執行之後織入增強處理
around 和 afterReturning 都可以修改返回結果。不過兩者的原理不同:
a、 around:可以任意修改,或者返回不相關的值。這個返回值完全可以自主控制
b、 afterReturning,通過方法參數 ,使用對象引用的方式來修改對象。修改對象引用地址那麼修改時無效的
除此之外從輸出結果來看,增強處理是有序的:
around 和 afterReturning小結:
a、 只有 around 和 afterReturning 可以獲取並修改返回結果。需要注意兩種方式修改的區別。
b、 around 需要線程安全
c、 雖然增強處理都需要 切入點表達式,並不是都支持 pointcut 屬性,所以最好都是用value 屬性指定。當註解只需要value屬性時,value可以省略
7、 @Pointcut
修飾方法,定義一個切入點表達式用於被其他增強調用。使用該方式定義切入點方便管理,易復用。
切入點方法定義和測試方法定義類似,具有以下特點:
a、 無返回值 (void)
b、 無參數
c、 方法體為空
d、 方法名就是切入點名稱
e、 方法名不能為 execution
切入點表達式
切入點表達式可以通過 && 、 || 、 ! 連接
1)、execution 表達式:
2)、within 表達式:
a、匹配指定類下的所有方法。
b、匹配執行包及其子包下所有類的所有方法。
所以within可以看做execution的簡寫,不需要指定返回類型、方法名、參數( 最小作用單位是類 )
3)、 @annotation:匹配使用指定註解修飾的目標方法;
匹配使用@CustomMethodAnnotation註解的目標方法。
4)、 @within: 用於匹配使用指定註解修飾的類下的所有方法
within 作用范圍是類,@within的作用范圍與其一致。不同的是@within 指定的不是類而是註解
匹配使用@ResponseBody 註解的類 下的所有方法。
AOP小結:
1)、 Around增強處理通常需要 在線程安全 的環境下使用
2)、 使用 around 和 afterReturning 可以獲取並修改返回結果
3)、 增強處理指定 切入點表達式時,最好使用value 屬性
4)、 切入點 名稱(方法名)不能為 execution
5)、 AfterReturning 指定了 returning 屬性接受目標方法返回結果,注意 參數類型需要和返回結果類型一致(滿足 resutType instanceof argsType )
增強方式的順序:
1、 @Bean(name=「xxx」)
修飾方法,該方法的返回值為spring容器中管理的bean。當然該註解和上面的@Component效果一樣,主要用於做區分。
@Bean 通常使用在 @Configuration 修飾的配置類中,該註解功能相當於 元素
常用的屬性:
a、 name:bean id 。name可以省略,省略時bean名稱為方法名。也可以指定多個名稱(逗號隔開)。
b、 autowire: 是否自動注入,默認Autowire.NO
c、 initMethod:bean的初始化方法。在依賴注入之後執行
d、 destroyMethod: spring容器關閉時bean調用的方法
當然 @Bean 還可以配合 @Scope 指定bean的作用域
2、 @ConfigurationProperties
用於從屬性文件中獲取值 application.properties 或者 application.yml 。當然了 如果在配置文件中引入其他配置文件,也可以獲取到屬性值。
包含的屬性:
a、 value | prefix 兩者互為別名。指定前綴,默認為""
b、 ignoreUnknownFields:默認為true。是否忽略未知欄位,當實體中的欄位在配置文件中不存在時,是忽略還是拋出異常
c、 ignoreInvalidFields: 默認false。 是否忽略不合法的欄位,此處的不合法是指類型不合適,配置文件中存在改配置但是無法轉化為指定的欄位類型。
Mybatis屬性配置
application.properties:
ConfigurationProperties 可以配置前綴,然後會根據實體的變數名拼接前綴,去配置文件中查詢配置。
3、 @Configuration
修飾一個Java類,被修飾的類相當於一個xml配置文件。功能類似於 。在springboot中大量使用了該註解,該註解提供了一種使用Java類方式配置bean。
可以發現 @Configuration使用了@Component 註解修飾。
實例 :
配置Mybatis會話工廠
4、 @Import
功能和 類似,修飾Java類,用於向當前類導入其他配置類。 可以導入多個配置文件,通常用於導入不在包掃描范圍內的配置文件。可以被掃描的配置類可以直接訪問,沒有必要使用@Import 導入。
比如 SpringBoot的啟動類指定的包掃描路徑為 com.example
資料庫的配置文件在 com包下。
在MyBatisConfig 中引入 DataSourceConfig, 就會解析DataSourceConfig。將解析出的Bean交給容器管理
5、 @ImportResource
修飾Java類,用於向類引入xml配置文件。
用於導入包含bean定義的配置文件,功能和 類似。默認情況下可以處理後綴為 .groovy 和.xml 的配置文件
6、 @Value("${expression}")
修飾成員變數或者 方法、構造器的參數,用於屬性值注入(在配置文件中配置的值)。
注意: @Value不能對 static 屬性注入。
如果的確需要注入到靜態變數,可以通過以下方式間接進行注入:
1)、設置一個私有靜態 實例
2)、通過構造函數或者 @PostConstruct 註解為 靜態實例 賦值,指向本身(this)
3)、對成員屬性注入內容
4)、提供靜態方法,使用靜態實例獲取成員屬性
7、@PropertySource(value=「classpath:jdbc.properties」)
該註解用來載入屬性文件。
常用屬性:
a、 ignoreResourceNotFound: 當資源文件找不到的時候是否會忽略該配置,而不是拋出錯誤。一般用於可選項
b、 encoding : 資源文件使用什麼編碼方式
c、 value : 指定屬性文件位置。可以配置多個屬性文件,不可以使用通配符。
在 PropertySource 中可以指定多個路徑,並且會將屬性文件中的值載入到 Environment 中。
@ConfigurationProperties 和 @PropertySource
它們的使用有一些差異:
1)、 @PropertySource 使用該註解載入的是 相對獨立的屬性文件,可以同時載入多個文件 (xxx.properties),而且 不支持自動注入 , 不支持前綴注入
2)、 @ConfigurationProperties 用於載入配置文件(application.properties | application.yml)。該註解功能更強大:
a、 支持前綴注入 ( prefix )
b、 相同屬性名的自動注入
c、 $("") 支持EL表達式注入
應用實例:
在以往的開發中通常會將資料庫連接信息存放在單獨的屬性文件中(jdbc.properties)。而在spring boot 中我們會將資料庫的信息存放在配置文件中,這會極大便利開發工作。
jdbc.properties:
可以通過 @Value 註解將配置文件的值注入到實體類中
也可以注入Environment ,通過Environment 獲取值
1、 @ResponseBody
控制器方法返回值會使用 HttpMessageConverter 進行數據格式化,轉化為jsON字元串。
同樣的 ResponseBodyAdvice: 針對使用@ResponseBody的註解的類,方法做增強處理。
2、 @RestController
@RestController = @Controller + @ResponseBody , 所以通常直接使用@RestController 註解
3、 @RequestBody
從Reuqest請求體中獲取內容,綁定到方法的指定參數上。 SpringMVC 使用HttpMessageConverter 介面將請求體中的數據轉化為方法參數類型。
SpringMVC 給用戶對參數的處理提供了很大支配權。 我們可以使用 介面RequestBodyAdvice 來實現對參數進行攔截處理。
注意
1)、 RequestBodyAdvice : 針對所有以@RequestBody的參數做處理
2)、 自定義的處理對象類上必須得加上@ControllerAdvice註解!
利用此功能我們可以做以下處理工作:
1)、參數做解密處理。
2)、修改接受的參數數據。
4、 @RequestParam
從Request請求中獲取指定的參數。
可以設置的屬性:
1)、 required : 默認為true 參數必須存在 。參數不存在時拋出異常(). 提示信息
2)、 defaultValue : 設置參數默認值。 當參數沒有提供或者為空值時生效, 包含隱式定義 required=false
3)、 name | value , 互為別名的屬性, 綁定請求中的參數名。 request.getParameter(name);
5、 @RequestMapping
用於設置 請求 和 Method 的映射關系。指明何種請求可以和方法匹配
可配置屬性值:
1)、 path、value、 name, 互為別名,設置可以處理的url。
2)、 consumes,字元串數組。 指定可以處理的 媒資類型,僅當請求頭中的 Content-Type 與其中一種媒體類型匹配時,才會映射請求。所以該配置會縮小可匹配的請求。 當url 匹配但是consumes不匹配時, 狀態碼415。 不設置的話,表示不限制媒資類型,參數的具體使用何種方式解析,SpringMVC會選擇合適的處理器處理。
3)、 proces,字元串數組。 生成的媒資類型,該屬性會影響實際的輸出類型。和consumes一樣,改配置會縮小匹配的范圍。 只有當請求頭中的 Accept 與 配置的任意一個媒資類型匹配時,才會映射請求。 當url 匹配與consumes不匹配時, 狀態碼406 。 比如:為了生成UTF-8編碼的JSON響應,應使用 MediaType.APPLICATION_JSON_UTF8_VALUE。
6. springboot配置文件總結
springboot 本身支持多種靈活的配置方式,為開發 springboot 程序帶來了很大的靈活性和擴展性,但是同時由於太靈活,經常會導致明明配置了相關屬性,卻沒有生效。
本文總結了 springboot 配置文件的原理以及多個配置文件生效的順序。
springboot 配置文件支持靈活的路徑,以及靈活的文件名,用一個變數表達式總結如下:
部分源碼如下:
當滿足上述變數表達式的配置文件有多個時,會有一個配置的優先順序。假設
上面每個條件組合起來,則最多有配置文件如下,且順序從上到下:
獲取屬性時,按從上到下的順序遍歷由上述文件生成的屬性資源對象 PropertySource ,如果遇到匹配的key直接返回。
總結一下:就是如果同一個key的屬性只出現一次,則直接取該值即可。如果同一個key的屬性出現多次,則取順序靠前的屬性資源對象。另外其中每個文件都是可選的。
需要注意的一點是:如果在同一個 location 下配置了多個文件名一樣的文件,則只會取一個,比如在 classpath:/ ,有如下兩個文件 application.yml :
則只會根據 classloader 的 classpath 列表,選取第一個出現的文件。因為 springboot 載入配置文件時最底層是使用的下面的方法:
這兩個方法只會獲取 classloader 類的 ucp 屬性裡面第一個匹配到的值。如果對 springboot 自身的機制不滿意,想獲取所有的classpath:/路徑下面的 applicaiton.yml 文件,可以使用下面的方法:
本文總結了 springboot 配置文件的原理以及多個配置文件生效的順序。如果存在增加了配置文件或者在配置文件裡面增加了屬性卻沒有生效,可以參考上面的 springboot 配置文件表達式和配置文件生效順序進行排查。
後面還會有一篇文章討論基於 springboot 配置原理如何實現自定義的配置讀取方式。
7. Spring Boot 配置的優先順序
本文主要參考 Externalized Configuration
為了能讓應用在不同的環境下運行,Spring Boot允許自定義配置文件,如properties文件、yaml文件、系統環境變數參數、命令行參數。配置文件的覆蓋優先順序如下
Developer Tools 提供了一些開發幫助工具,在build.gradle添加依賴後啟用。
Spring Boot會讀取在計算機用戶的home目錄下的 .spring-boot-devtools.properties 文件里的配置參數到該計算級的所有Spring Boot應用中作為頂層配置,岩頃顫如Linux環境下root用戶下 ~/.spring-boot-devtools.properties 文件。開發過程中,可以將一些個人參數記錄在這個配置文件中,例如ip地址,機器uuid,datasource參數等。在該配置文件中的定義的配置環境並不會影響到應用配置的讀取,官方原話是:
但要注意,該配置優先順序最高,設置的時候需要做好記錄否則會出現"原因不明的bug",不過應該很少人會用到這個功能。分析下源碼,就是加了一個配置切面,並把其設置為頂層配置:
在測試的時候,可能會使用另一套測試專用的配置,該套配置的優先順序高於系統環境變數、java系統參數、程序內部參數, @TestPropertySource 註解就是用來指定這一類配置的。該註解一共有5個參數可以設置:
如果使用註解的時候沒有任何參數,那麼會從標注了註解的測試類的包中嘗試讀取配置文件,例如測試類 com.spring.test.DemoTest ,那麼相應的默認配置文件為 com.spring.test.DemoTest.properties ,如果沒有找到默認的配置文件則乎慎拋出非法狀態異常。
在初始化上下文的時候會調用一個讀取、合並配置的方法 ,該方法通過工具類 TestPropertySourceUtils 讀取類的註解信息。 TestPropertySourceUtils 從類的註解解析配置信息後返回一個可合並的粗敗配置源。
@SpringBootTest 的value\properties屬性用於注入一些自定義的註解,語法要求和 @TestPropertySource 的properties一樣,這里就不詳細展開了。
用命令行方式啟動Spring Boot應用程序的時候,可以注入一些配置參數,參數的格式是 --key=name 。舉個簡單的例子,程序直接輸出一個參數,然後打成jar包後運行。
運行:
java -jar .\springbootconfiguraiton.jar --cl.name="Spring Boot Arguments"
從輸出的結果中可以看到可以讀取到命令行中的配置。
可以在環境變數中定義一個key為SPRING_APPLICATION_JSON的參數,值為json字元串,Spring Boot會解析該json字元串作為參數注入到系統中。SPRING_APPLICATION_JSON可以定義在環境變數、系統配置中,命令行也是可以的,例如命令行參數中用到的demo,執行以下的命令也應該能得到相同的參數結果。
java -jar .\springbootconfiguraiton.jar SPRING_APPLICATION_JSON='{"cl":{"name"="Spring Boot Arguments"}}'
結果輸出是undefined,不知道原因,這個配置方式用的應該也很少,放棄研究。。。
優先順序是 ServletConfig > ServletContext ,可以在application.yml中設置:
隨機數配置大多用於測試,支持的類型如下:
其中long\int可以限制數據范圍,[]是閉區間,()是開區間。
這個應該是我們用的最多的。首先說優先順序,文件可以放在以下4個位置,相同文件從上到下覆蓋。外部指的是啟動應用程序的目錄,例如gradle用application插件打包後,運行的腳本目錄就是 ./ :
文件的命名為 application-[當前激活的環境名].[yml/properties] ,當前激活的配置可以用 spring.profile.active=[當前激活的環境名] 定義,多個環境名用逗號分隔,未設置時用 default 標識。關於如果修改默認的載入路徑和文件名,後面會繼續討論。
Spring Boot系統啟動時默認會讀取的配置文件,支持properties\yml格式。也就是說,會先載入 application.properties ,根據 spring.profile.active 的設置載入相應的 application-XX.properties 配置,然後按優先順序合並配置文件。
不同文件目錄下application.properties的優先順序和 自定義配置文件 的順序是一樣的。
類似 @TestPropertySource註解 ,在項目中可以方便的注入自定義的配置文件,註解一共有5個參數:
8. 二、springboot配置文件
1. 配置文件
Spring Boot使用一個全局的配置文件
application.properties
application.yml
配置文件的作用:修改Spring Boot自動配置的默認值,SpringBoot在底層都給我們自動
配置好。有什麼配置項,可以移步官方文檔
配置文件一般放在src/main/resources目錄或者類路徑/confifig下,當然還有很多位置可
以放,它們會有不同優先順序,後面會講到。
YAML (YAML Ain't Markup Language)
簡單介紹
<!--綁定配置文件處理器,配置文件進行綁定的時候就會有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 將應用打包成一個可執行Jar包,直接使用java -jar xxxx的命令來執行 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>以前的配置文件:大多是xml
.yml是YAML語言的文件,以數據為中 心,比json、xml等更適合做配置文件
全局配置文件的可以對一些默認配置值進行修改
配置實例
xml:
yml:
2. YAML語法
基本語法
K:(空格)V 標識一對鍵值對
以空格的縮進來控制層級關系
只要是左對齊的一列數據,都是同一層級的
屬性和值也是大小寫敏感
實例:
值的寫法
普通的值
k: v 字面量直接來寫,字元串默認不用添加單引號
" " 雙引號 不會轉義字元串裡面的特殊字元;
<server>
<port>8081</port>
</server>
server:
port: 8081
server:
port: 8081
path: /hello // 冒號後面的空格不要拉下' ' 單引號 會轉義字元,特殊字元最終是一個普通的字元串
對象
普通寫法:
行內寫法
frends:{ lastName: zhang,age: 18 }
Map
示例:
maps: {k1: v1,k2: v2}
數組
普通寫法:
pets: // var onj = {pets: ['cat','pig','dog']}
- cat
- pig
- dog
行內寫法
pets:[cat, pig, dog]
配置文件獲取
將配置文件中的每一個值映射到此組件中
1. Persion
name: "wang \n qian" // 輸出:wang 換行 qian
frends:
lastName: zhang
age: 20package com.wrq.boot.bean;
@Component
@ConfigurationProperties(prefix = "persion")
public class Persion {
private String name;
private int age;
private double weight;
private boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> list;
private Dog dog;
此處,這個bean的getter、setter和tostring方法已經省略,千萬不能忽略!
}
@ConfifigurationProperties 意思是:我們類裡面的屬性和配置文件中的屬性做綁定
不使用此註解,可以在bean的屬性添加@value()註解,如下:
@Component
// @ConfigurationProperties(prefix = "persion")
public class Persion {
@value("${persion.name}") // $()讀取配置文件、環境變數中的值
private String name;
@value("#{11*2}") // #{SpEL} 採用表達式
private int age;
@value("true") // 直接賦值
private boolean boos;
}
此處採用@ConfifigurationProperties的方式,@value()和@ConfifigurationProperties的
區別見下方表格。prefifix = "persion" 配置文件中那個下面的屬性來一一映射
@Component 如果想要這個註解起作用,必須放到容器裡面
2. Dog
package com.wrq.boot.bean;
public class Dog { // 用作Persion中的屬性
private String name;
private int age;
此處,這個bean的getter、setter和tostring方法已經省略,千萬不能忽略!
}
3. 配置文件
方式一: application.yml
persion:
name: 王大錘
age: 18
weight: 125
boss: false
birth: 2018/5/5
maps: {k1: v1,k2: v2}
list:
- wangli
- wang
dog:
name: xiaogou
age: 2
方式二: application.propertiespersion.name = 王大錘
persion.age = 18
persion.weight = 125
persion.boss = false
persion.birth = 2018/5/5
persion.maps.k1 = v1
persion.maps.k2 = v2
persion.dog.name = xiaogou
persion.dog.age = 15
4. 測試類:BootApplicationTests
package com.wrq.boot;
@RunWith(SpringRunner.class)
@SpringBootTest
public class BootApplicationTests {
@Autowired
Persion persion;
@Test
public void contextLoads() {
System.out.print(persion);
}
}
5. 運行 BootApplicationTests方法
控制台列印:
application.yml的結果:
Persion{name='王大錘', age=18, weight=125.0, boss=false, birth=Sat May
05 00:00:00 CST 2018, maps={k1=v1, k2=v2}, list=[wangli, wang],
dog=Dog{name='xiaogou', age=2}}
application.properties的結果:
Persion{name='��Ǭ', age=18, weight=125.0, boss=false, birth=Sat
May 05 00:00:00 CST 2018, maps={k2=v2, k1=v1}, list=[wangli, wang],
dog=Dog{name='xiaogou', age=15}}
把Bean中的屬性和配置文件綁定,通過yml文件和properties都可以做到,但是properties
文件出現亂碼。
properties中文讀取亂碼:File->Settings->File Encodings最底部選utf-8、Tranparent打
上勾
註解比較
@value和@ConfifigurationProperties獲取值比較
名詞解釋:
鬆散綁定
last-name和lastName都可以獲取導致,則代表支持鬆散綁定
JSR303@Component
@ConfigurationProperties(prefix = "persion") // 如果使用的是@value注入值
時,無法使用校驗
@Validated // 添加此註解
public class Persion {
@Email // 配置文件書寫的屬性必須是郵箱格式,不符合報錯!
private String name;
}
復雜類型封裝
如果獲取配置文件中map的值時,@value是獲取不到值的
@value("${persion.maps}") // 由於使用的是@value,無法獲取配置文件中的map
private Map<String,Object> maps;
@PropertySource
@PropertySource:載入指定配置文件
@ConfifigurationProperties()默認是從全局配置文件中獲取值,也就是
application.properties這個文件中獲取值。
如果做的配置很多,全局的配置文件就會特別大,為了方便管理。我會創建不同的配置文
件定向管理不同的配置。
如創建persion.properties文件單獨存放persion需要的配置
@PropertySource就是用來導入創建的配置文件
示例:
1. persion.properties
同時把兩個全局的配置中關於Persion的配置都注釋掉persion.name = 王弟弟
persion.age = 18
persion.weight = 125
persion.boss = false
persion.birth = 2018/5/5
persion.maps.k1 = v1
persion.maps.k2 = v2
persion.dog.name = xiaogou
persion.dog.age = 15
2. Persion
package com.wrq.boot.bean;
@Component
@PropertySource(value = {"classpath:persion.properties"})
@ConfigurationProperties(prefix = "persion")
public class Persion {
private String name;
private int age;
private double weight;
private boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> list;
private Dog dog;
此處,這個bean的getter、setter和tostring方法已經省略,千萬不能忽略!
}
這樣運行測試類,控制台就可以列印persion.properties中的數據。
通過下面的註解,把類路徑下的persion.properties載入進來。並且把persion開頭的數
據進行綁定。
@PropertySource(value = {"classpath:persion.properties"})@ConfifigurationProperties(prefifix = "persion")
@ImportResource
@ImportResource:導入Spring的配置文件,讓配置文件生效。
示例:
1. com.wrq.boot.service
package com.wrq.boot.service;
/**
* Created by wangqian on 2019/1/12.
*/
public class HelloService {
}
2. resources目錄手動建立bean.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.wrq.boot.service.HelloService">
</bean>
</beans>
3. 測試類
package com.wrq.boot;
@RunWith(SpringRunner.class)
@SpringBootTest
public class BootApplicationTests {
@Autowired
ApplicationContext ioc;@Test
public void testConfig() {
boolean b = ioc.containsBean("helloService");
System.out.print(b);
}
}
試圖通過添加一個Spring的配置文件bean.xml來把HelloService注入進去。
運行測試類結果:false
結果表明IoC容器中並不包含HelloService,即:配置文件bean.xml沒有生效
解決方式
方式一: 主程序中進行配置@ImportResouece註解
package com.wrq.boot;
@ImportResource(locations = {"classpath:bean.xml"}) // 通過此配置是
bean.xml生效
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
//應用啟動起來
SpringApplication.run(BootApplication.class, args);
}
}
方法二:通過配置類實現,這種方式也是Spring Boot推薦的
1. com.wrq.boot.confifigpackage com.wrq.boot.config;
/**
* Created by wangqian on 2019/1/12.
*/
@Configuration
public class MyConfig {
// 將方法的返回值添加到容器之中,並且容器中這個組件的id就是方法名
@Bean
public HelloService helloService(){
System.out.print("通過@Bean給容器添加組件了..");
return new HelloService();
}
}
@Confifiguration標注這是一個配置類
通過@Bean註解,將方法的返回值添加到容器之中,並且容器中這個組件的id就是方
法名
2. 把主程序類中@ImportResource()配置注釋掉
3. 測試成功,添加了HelloService()組件
3. 配置文件佔位符
隨機數
RandomValuePropertySource:配置文件中可以使用隨機數
${random.value}
${random.int}
${random.long}
${random.uuid}
${random.int(10)}
${random.int[1024,65536]}
屬性配置佔位符可以在配置文件中引用前面配置過的屬性(優先順序前面配置過的這里都能用)
${app.name:默認值}來指定找不到屬性時的默認值
persion.name = 王弟弟${random.uuid}
persion.age = ${random.int}
persion.dog.name = ${persion.name}_dog
4. Profifile 多環境支持
Profifile是Spring對不同環境提供不同配置功能的支持,可以通過激活、 指定參數等方式
快速切換環境
1. 多Profifile的方式
格式:application-{profifile}.properties/yml
application-dev.properties
application-prod.properties
默認採用application.properties配置文件,如果使用別的,需要激活:
1. application.properties中配置:
# 激活application-dev.properties配置文件
spring.profiles.active=dev
2. application-dev.properties:
server.port=8082
3. 運行BootApplication主程序:
2019-01-12 20:46:09.345 INFO 14404 --- [main]
s.b.c.e.t. : Tomcat started on port(s):
8082 (http)
2. 多文檔塊的方式
除了上方多Profifile的方式來切換環境,也可以通過YAML多文檔塊的方式。示例:
application.yml:
server:
port: 8081
spring:
profiles:
active: dev
---
spring:
profiles: dev
server:
port: 8083
---
spring:
profiles: prod
server:
port: 8084
3. 激活指定Profifile
1. application.properties中配置:
# 激活application-dev.properties配置文件
spring.profiles.active=dev
2. application.yml中配置
server:
port: 8081
spring:
profiles:
active: dev
---
spring:
profiles: dev
server:
port: 80833. 啟動配置-參數
在IDE中,類似於配置tomcat的地方,按下方配置:
Program arguments:--spring.profiles.active=dev
4. 啟動配置-虛擬機
在IDE中,類似於配置tomcat的地方,按下方配置:
VM options:-Dspring-profiles-active=dev
5. 命令行 使用Maven的package命令打包,移動到jar的目錄。
java -jar spring-boot-project-config.jar --spring.profiles.active=dev
5. 配置文件優先順序
GitHub對應項目:boot-confifig-position
優先順序
Spring Boot 啟動會掃描以下位置的application.properties或者 application.yml文件作
為Spring boot的默認配置文件
fifile:./confifig/ (項目根目錄confifig文件夾下的配置文件)
fifile:./ (項目根目下的配置文件)
classpath:/confifig/ (resources目錄confifig文件夾下的配置文件)
classpath:/ (resources目下的配置文件)
以上是按照優先順序從高到低的順序,所有位置的文件都會被載入,高優先順序配置內容會覆
蓋低優先順序配置內容,形成互補配置。
默認配置
我們也可以通過配置spring.confifig.location來改變默認配置。
項目打包後以後,我們可以使用命令行參數的形式,啟動項目的時候來指定配置文件的新
位置;指定配置文件和默認載入的這些配置文件共同起作用,形成互補配置。
1. Maven->package對項目打包2. 把待使用的配置文件放在本地文件夾中,如:D:/application.properties
3. 命令行執行命令
java -jar boot-config-position-xxxxxx.jar --
spring.config.location=D:/application.properties
這樣即使項目上線了,我們也可以通過修改本地的配置文件,使用一行命令即可,極大方
便了運維人員。
6. 外部配置載入順序
Spring Boot 支持多種外部配置方式
可以從以下位置載入配置,優先順序從高到低,高優先順序配置覆蓋低優先順序的,所以配置形
成互補配置。
1. 命令行參數
java -jar boot-config-position-xxxxxx.jar --server.port // 多個配置用空格
隔開
2. 來自java:comp/env的JNDI屬性
3. Java系統屬性(System.getProperties())
4. 操作系統環境變數
5. RandomValuePropertySource配置的random.*屬性值
6. jar包外部的application-{profifile}.properties或application.yml(帶spring.profifile)配
置文件
7. jar包內部的application-{profifile}.properties或application.yml(帶spring.profifile)配
置文件
8. jar包外部的application.properties或application.yml(不帶spring.profifile)配置文件
9. jar包內部的application.properties或application.yml(不帶spring.profifile)配置文件
10. @Confifiguration註解類上的@PropertySource
11. 通過SpringApplication.setDefaultProperties指定的默認屬性
注意:從jar包外向jar包內尋找,優先載入profifile最後載入不帶profifile,更多參考官方文
檔
7. 自動配置原理GitHub對應項目:boot-confifig-autoconfifig
1. 配置文件寫什麼?
配置文件可配置屬性查閱
2. 什麼是註解,如何實現一個註解?
關於註解的機制和相關原理可以移步此篇博客
3. 配置原理解析
我們運行Spring Boot應用是從main方法啟動,在主程序類上有一個
@SpringBootApplication註解。
@SpringBootApplication是一個復合註解,包括@ComponentScan,和
@SpringBootConfifiguration,@EnableAutoConfifiguration。
@SpringBootConfifiguration繼承自@Confifiguration,二者功能也一致,標注當前類
是配置類,並會將當前類內聲明的一個或多個以@Bean註解標記的方法的實例納入到
srping容器中,並且實例名就是方法名。
@EnableAutoConfifiguration的作用啟動自動的配置,@EnableAutoConfifiguration注
解的意思就是SpringBoot根據你添加的jar包來配置你項目的默認配置,比如根據
spring-boot-starter-web ,來判斷你的項目是否需要添加了webmvc和tomcat,就
會自動的幫你配置web項目中所需要的默認配置
@ComponentScan,掃描當前包及其子包下被@Component,@Controller,
@Service,@Repository註解標記的類並納入到spring容器中進行管理。是以前的co
ntext:component-scan(以前使用在xml中使用的標簽,用來掃描包配置的平行支
持)。
@SpringBootApplication註解分析
配置原理視頻講解
4. 自動配置類判斷
在配置文件properties中設置:debug=true 來讓控制台列印自動配置報告,方便的得知
那些配置類生效。
=========================
AUTO-CONFIGURATION REPORT
=========================Positive matches:
-----------------
matched:
- @ConditionalOnClass found required class
'org.springframework.web.servlet.DispatcherServlet';
@ConditionalOnMissingClass did not find unwanted class
(OnClassCondition)
- @ConditionalOnWebApplication (required) found 'session' scope
(OnWebApplicationCondition)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes
'javax.jms.ConnectionFactory',
'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)