[原]Spring boot(2)-配置詳解
1、自動化配置
Spring Boot 對于開發人員最大的好處在于可以對 Spring 應用進行自動配置。Spring Boot 會根據應用中聲明的第三方依賴來自動配置 Spring 框架,而不需要進行顯式的聲明。比如當聲明了對 HSQLDB 的依賴時,Spring Boot 會自動配置成使用 HSQLDB 進行數據庫操作。
Spring Boot 推薦采用基于 Java 注解的配置方式,而不是傳統的 XML。只需要在主配置 Java 類上添加“@EnableAutoConfiguration”注解就可以啟用自動配置。Spring Boot 的自動配置功能是沒有侵入性的,只是作為一種基本的默認實現。開發人員可以通過定義其他 bean 來替代自動配置所提供的功能。比如當應用中定義了自己的數據源 bean 時,自動配置所提供的 HSQLDB 就不會生效。這給予了開發人員很大的靈活性。既可以快速的創建一個可以立即運行的原型應用,又可以不斷的修改和調整以適應應用開發在不同階段的需要。可能在應用最開始的時候,嵌入式的內存數據庫(如 HSQLDB)就足夠了,在后期則需要換成 MySQL 等數據庫。Spring Boot 使得這樣的切換變得很簡單。
2、外部化的配置
在應用中管理配置并不是一個容易的任務,尤其是在應用需要部署到多個環境中時。通常會需要為每個環境提供一個對應的屬性文件,用來配置各自的數據庫連接信息、服務器信息和第三方服務賬號等。通常的應用部署會包含開發、測試和生產等若干個環境。不同的環境之間的配置存在覆蓋關系。測試環境中的配置會覆蓋開發環境,而生產環境中的配置會覆蓋測試環境。Spring 框架本身提供了多種的方式來管理配置屬性文件。Spring 3.1 之前可以使用 PropertyPlaceholderConfigurer。Spring 3.1 引入了新的環境(Environment)和概要信息(Profile)API,是一種更加靈活的處理不同環境和配置文件的方式。不過 Spring 這些配置管理方式的問題在于選擇太多,讓開發人員無所適從。Spring Boot 提供了一種統一的方式來管理應用的配置,允許開發人員使用屬性文件、YAML 文件、環境變量和命令行參數來定義優先級不同的配置值。
Spring Boot 所提供的配置優先級順序比較復雜。按照優先級從高到低的順序,具體的列表如下所示。
- 命令行參數。
- 通過 System.getProperties() 獲取的 Java 系統參數。
- 操作系統環境變量。
- 從 java:comp/env 得到的 JNDI 屬性。
- 通過 RandomValuePropertySource 生成的“random.*”屬性。
- 應用 Jar 文件之外的屬性文件。
- 應用 Jar 文件內部的屬性文件。
- 在應用配置 Java 類(包含“@Configuration”注解的 Java 類)中通過“@PropertySource”注解聲明的屬性文件。
- 通過“SpringApplication.setDefaultProperties”聲明的默認屬性。
Spring Boot 的這個配置優先級看似復雜,其實是很合理的。比如命令行參數的優先級被設置為最高。這樣的好處是可以在測試或生產環境中快速地修改配置參數值,而不需要重新打包和部署應用。
命令行參數
通過 Java -jar app.jar --name="Spring" --server.port=9090 方式來傳遞參數。
SpringApplication 類默認會把以“--”開頭的命令行參數轉化成應用中可以使用的配置參數,如 “--name=Alex” 會設置配置參數 “name” 的值為 “Alex”.
可以使用的參數可以是我們自己定義的,也可以是Spring Boot中默認的參數。
注意: 命令行參數在 app.jar 的后面!
可以通過 SpringApplication.setAddCommandLineProperties(false) 禁用命令行配置。
Java系統屬性
注意Java系統屬性位置 java -Dname="isea533" -jar app.jar ,可以配置的屬性都是一樣的,優先級不同。
例如 java -Dname="isea533" -jar app.jar --name="Spring!" 中 name 值為 Spring.
有些系統,關于一些數據庫或其他第三方賬戶等信息,由于安全問題,其配置并不會提前配置在項目中暴露給開發人員。
對于這種情況,我們在運行程序的時候,可以通過參數指定一個外部配置文件。
以 demo.jar 為例,方法如下:
java -jar demo.jar --spring.config.location=/opt/config/application.properties
其中文件名隨便定義,無固定要求。
RandomValuePropertySource
RandomValuePropertySource 可以用來生成測試所需要的各種不同類型的隨機值,從而免去了在代碼中生成的麻煩。RandomValuePropertySource 可以生成數字和字符串。數字的類型包含 int 和 long,可以限定數字的大小范圍。以“random.”作為前綴的配置屬性名稱由 RandomValuePropertySource 來生成:
系統中用到隨機數的地方,例如 使用 RandomValuePropertySource 生成的配置屬性:
user.id=${random.value}
user.count=${random.int}
user.max=${random.long}
user.number=${random.int(100)}
user.range=${random.int[100, 1000]
random.int* 支持 value 參數和 ,max 參數,當提供 max 參數的時候, value 就是最小值
3、屬性文件
3.1 屬性配置文件的位置
屬性文件是最常見的管理配置屬性的方式。Spring Boot 提供的 SpringApplication 類會搜索并加載 application.properties 或 application.yml 文件來獲取配置屬性值。SpringApplication 類會在下面位置搜索該文件。
- 當前目錄的“/config”子目錄。
- 當前目錄。
- classpath 中的“/config”包。
- classpath
上面的順序也表示了該位置上包含的屬性文件的優先級。優先級按照從高到低的順序排列。 即:/config優先于classpath根目錄
可以通過“spring.config.name”配置屬性來指定不同的屬性文件名稱。也可以通過“spring.config.location”來添加額外的屬性文件的搜索路徑。如果應用中包含多個 profile,可以為每個 profile 定義各自的屬性文件,按照“application-{profile}”來命名。
3.2應用配置文件(.properties或.yml)
在配置文件 application.properties 中直接寫:
name=Isea533
server.port=8080
.yml格式的配置文件如:
name: Isea533
server:
port: 8080
當有前綴的情況下,使用.yml格式的配置文件更簡單。關于.yml配置文件用法 請看 這里
注意:使用.yml時,屬性名的值和冒號中間必須有空格,如name: Isea533正確,name:Isea533就是錯的。
3.3 @PropertySource優先級比較
這個注解可以指定具體的屬性配置文件,優先級比較低。
SpringApplication.setDefaultProperties
例如:
SpringApplication application = new SpringApplication(Application.class);
Map<String, Object> defaultMap = new HashMap<String, Object>();
defaultMap.put("name", "Isea-Blog");
//還可以是Properties對象
application.setDefaultProperties(defaultMap);
application.run(args);
3.5 應用程序使用屬性 @Value(“${xxx}”)
對于配置屬性,可以在代碼中通過“@Value”來使用,如:
@RestController
@EnableAutoConfiguration
public class Application {
@Value("${name}")
private String name;
@RequestMapping("/")
String home() {
return String.format("Hello %s!", name);
}
}
變量 name 的值來自配置屬性中的“name”屬性。
比如application.properties有 port=8081
則
<p>@Value("${port:8082}")</p>private String port;
即可獲取8081這個值
3.6屬性占位符
例如:
app.name=MyApp
app.description=${app.name} is a Spring Boot application
可以在配置文件中引用前面配置過的屬性(優先級前面配置過的這里都能用)。
通過如${app.name:默認名稱}方法還可以設置默認值,當找不到引用的屬性時,會使用默認的屬性。
由于${}方式會被Maven處理。如果你pom繼承的spring-boot-starter-parent,Spring Boot 已經將maven-resources-plugins默認的${}方式改為了@ @方式,例如@name@。
如果你是引入的Spring Boot,你可以修改使用其他的分隔符
3.7通過屬性占位符還能縮短命令參數
例如修改web默認端口需要使用--server.port=9090方式,如果在配置中寫上:
server.port=${port:8080}
那么就可以使用更短的--port=9090,當不提供該參數的時候使用默認值8080。
3.8屬性名匹配規則
例如有如下配置對象:
@Component
@ConfigurationProperties(prefix="person")
public class ConnectionSettings {
private String firstName;
}
firstName可以使用的屬性名如下:
person.firstName,標準的駝峰式命名
person.first-name,虛線(-)分割方式,推薦在.properties和.yml配置文件中使用
PERSON_FIRST_NAME,大寫下劃線形式,建議在系統環境變量中使用
3.9屬性驗證
可以使用JSR-303注解進行驗證,例如:
@Component
@ConfigurationProperties(prefix="connection")
public class ConnectionSettings {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}</code></pre>
4、自定義配置
spring boot使用application.properties默認了很多配置。但需要自己添加一些配置的時候,我們應該怎么做呢。
若繼續在application.properties中添加
如:
wisely2.name=wyf2
wisely2.gender=male2
定義配置類:
@ConfigurationProperties(prefix = "wisely2")
public class Wisely2Settings {
private String name;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}</code></pre>
若新用新的配置文件
如我新建一個wisely.properties
wisely.name=wangyunfei
wisely.gender=male
需定義如下配置類
@ConfigurationProperties(prefix = "wisely",locations = "classpath:config/wisely.properties")
public class WiselySettings {
private String name;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}</code></pre>
最后注意在spring Boot入口類加上@EnableConfigurationProperties
<p>@SpringBootApplication </p>
<p>@EnableConfigurationProperties({WiselySettings.class,Wisely2Settings.class}) </p>
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
使用定義的properties
在別的bean中可直接注入
@Controller
public class TestController {
@Autowired
WiselySettings wiselySettings;
@Autowired
Wisely2Settings wisely2Settings;
@RequestMapping("/test")
public @ResponseBody String test(){
System.out.println(wiselySettings.getGender()+"---"+wiselySettings.getName());
System.out.println(wisely2Settings.getGender()+"==="+wisely2Settings.getGender());
return "ok";
}
}</code></pre>
或者
在@Bean方法上使用@ConfigurationProperties
例如:
@ConfigurationProperties(prefix = "foo")
@Bean
public FooComponent fooComponent() {
...
}
Spring Boot 會將foo開頭的屬性按照名字匹配注入到FooComponent對象中。
涉及四個文件:
1:properties文件,這里是config.properties,放置在properties文件常放置的地方,即src/main/resources目錄下
2:一個存放properties配置文件屬性的Bean,這里是 WiselySettings . Java
4:在spring Boot入口類加上@EnableConfigurationProperties
3:讀取配置的Controller或者bean
5、YAML配置
相對于屬性文件來說,YAML 是一個更好的配置文件格式。YAML 在 Ruby on Rails 中得到了很好的應用。SpringApplication 類也提供了對 YAML 配置文件的支持,只需要添加對 SnakeYAML 的依賴即可。application.yml 文件的示例。
spring:
profiles: development
db:
url: jdbc:hsqldb:file:testdb
username: sa
password:
spring:
profiles: test
db:
url: jdbc:mysql://localhost/test
username: test
password: test</code></pre>
AML 文件同時給出了 development 和 test 兩個不同的 profile 的配置信息,這也是 YAML 文件相對于屬性文件的優勢之一。除了使用“@Value”注解綁定配置屬性值之外,還可以使用更加靈活的方式。YAML 文件的 Java 類:
@Component
@ConfigurationProperties(prefix="db")
public class DBSettings {
private String url;
private String username;
private String password;
}
通過“@ConfigurationProperties(prefix="db")”注解,配置屬性中以“db”為前綴的屬性值會被自動綁定到 Java 類中同名的域上,如 url 域的值會對應屬性“db.url”的值。只需要在應用的配置類中添加“@EnableConfigurationProperties”注解就可以啟用該自動綁定功能。
6. @EnableAutoCongiguration配置
從Spring 3.0開始,為了替代繁瑣的XML配置,引入了 @Enable... 注解對 @Configuration 類進行修飾以達到和XML配置相同的效果。想必不少開發者已經使用過類似注解:
- @EnableTransactionManagement 開啟Spring事務管理,相當于XMl中的 <tx:*>
- @EnableWebMvc 使用Spring MVC框架的一些默認配置
- @EnableScheduling 會初始化一個Scheduler用于執行定時任務和異步任務
Spring Boot提供的 @EnableAutoCongiguration 似乎功能更加強大,一旦加上,上述所有的配置似乎都被包含進來而無需開發者顯式聲明。它究竟是如何做到的呢,先看看它的定義:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ EnableAutoConfigurationImportSelector.class,
AutoConfigurationPackages.Registrar.class })
public @interface EnableAutoConfiguration {
/**
- Exclude specific auto-configuration classes such that they will never be applied.
*/
Class<?>[] exclude() default {};
}</code></pre>
EnableAutoConfigurationImportSelector 使用的是 spring-core 模塊中的 SpringFactoriesLoader#loadFactoryNames() 方法,它的作用是在類路徑上掃描 META-INF/spring.factories 文件中定義的類:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration</code></pre>
實際上這就是Spring Boot會自動配置的一些對象,例如前面提到的Web框架由 EmbeddedServletContainerAutoConfiguration , DispatcherServletAutoConfiguration , ServerPropertiesAutoConfiguration 等配置完成,而 DataSource 的自動配置則是由 DataSourceAutoConfiguration 完成。現在我們以Mongo的配置 MongoAutoConfiguration 為例,來探索Spring Boot是如何完成這些配置的:
@Configuration
@ConditionalOnClass(Mongo.class)
@EnableConfigurationProperties(MongoProperties.class)
public class MongoAutoConfiguration {
@Autowired
private MongoProperties properties;
private Mongo mongo;
@PreDestroy
public void close() throws UnknownHostException {
if (this.mongo != null) {
this.mongo.close();
}
}
@Bean
@ConditionalOnMissingBean
public Mongo mongo() throws UnknownHostException {
this.mongo = this.properties.createMongoClient();
return this.mongo;
}
}</code></pre>
首先這是一個Spring的配置 @Configuration ,它定義了我們訪問Mongo需要的 @Bean ,如果這個 @Configuration 被Spring Context掃描到,那么Context中自然也就有兩個一個 Mongo 對象能夠直接為開發者所用。
但是注意到其它幾個Spring注解:
- @ConditionOnClass 表明該 @Configuration 僅僅在一定條件下才會被加載,這里的條件是 Mongo.class 位于類路徑上
- @EnableConfigurationProperties 將Spring Boot的配置文件( application.properties )中的 spring.data.mongodb.* 屬性映射為 MongoProperties 并注入到 MongoAutoConfiguration 中。
- @ConditionalOnMissingBean 說明Spring Boot僅僅在當前上下文中不存在 Mongo 對象時,才會實例化一個Bean。這個邏輯也體現了Spring Boot的另外一個特性——自定義的Bean優先于框架的默認配置,我們如果顯式的在業務代碼中定義了一個 Mongo 對象,那么Spring Boot就不再創建。
接下來看一看 MongoProperties :
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
private String host;
private int port = DBPort.PORT;
private String uri = "mongodb://localhost/test";
private String database;
// ... getters/ setters omitted
}</code></pre>
顯然,它就是以 spring.data.mongodb 作為前綴的屬性,然后通過名字直接映射為對象的屬性,同時還包含了一些默認值。如果不配置,那么 mongo.uri 就是 mongodb://localhost/test 。
配置通用屬性
Spring Boot application.propertis配置文件的相關通用屬性
Spring Boot application.yaml配置文件的相關通用屬性
來自:http://blog.csdn.net/hguisu/article/details/51006252