如题,本篇我们介绍在springboot中多环境profile的使用。
在我们的项目开发、测试、上线过程中,不可避免的需要反复地修改配置文件。譬如,开发环境连接的数据库ip和测试、生产环境的不同;开发环境开发的app版本和测试、生产线上的app版本信息也不同,等等。。我们发现,尽管在springboot中使用application.properties (或者yml)作为整个项目的全局配置文件,但是生产、测试环境往往都会有些不同于开发环境的配置,这时候profile就派上用场了。
另外 ,使用profile还有个明显的用处——可以抽取application.yml中的配置信息到其他文件。
如当我们的项目越来越大时,项目配置信息太多,application.yml配置文件会比较大,这时我们可以通过定义profile,将一些配置信息从application.yml中抽取到一个单独的文件中,如建立:
application-devFtp.yml 只存放开发环境ftp相关的配置信息
application-devRedis.yml 只存放开发环境redis相关的配置信息
application-testFtp.yml 只存放测试环境ftp相关的配置信息
application-testRedis.yml 只存放测试环境redis相关的配置信息
然后在application.yml中 ,切换开发环境,配置spring.profiles.active=dev, devFtp,devRedis 来引入dev、devFtp、devRedis的配置即可。切换测试环境,配置spring.profiles.active=test, testFtp,testRedis 来引入test、testFtp、testRedis的配置 即可。
注意:properties的配置文件含中文时读取会乱码,而在yml中不会,因此建议大家使用yml配置文件替换properties配置文件
一、application.properties和application-{profile}.properties配置
profile允许在项目中同时配置多套与环境相关的配置,profile的文件名称为application-{profile}.properties(以properties文件为例),其中profile可以为dev(开发)、test(测试)、prod(生产)等,这些名称是用户自定义的。当需要切换到指定环境配置时,只需将application.properties中spring.profiles.active设置为指定的profile名称即可。 如:
application.properties
# profile 配置 dev test prod
spring.profiles.active=dev
#spring.profiles.active=test
#spring.profiles.active=prod
application-dev.properties
app.myname=dev_app
application-test.properties
app.myname=test_app
application-prod.properties
app.myname=prod_app
SpringContextEventHandler.java 中使用@Value("${app.myname}")注入值,并打印之
package com.tingcream.springWeb.spring.eventListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import com.tingcream.springWeb.common.SpringContextHelper;
import com.tingcream.springWeb.spring.event.MyAppEvent;
@Component
public class SpringContextEventHandler {
@Value("${app.myname}")
private String myname;
@EventListener
public void stopped(ContextStoppedEvent event){
System.out.println("SpringContextEventHandler stopped执行");
}
@EventListener
public void started(ContextStartedEvent event){
System.out.println("SpringContextEventHandler started执行");
}
@EventListener
public void refreshed(ContextRefreshedEvent event){
System.out.println("SpringContextEventHandler refreshed执行");
System.out.println("myname:"+myname);//打印@value注入的值
SpringContextHelper.getApplicationContext().publishEvent(new MyAppEvent("这是一段事件消息"));
}
@EventListener
public void closed(ContextClosedEvent event){
System.out.println("SpringContextEventHandler closed执行");
}
// ready
@EventListener
public void ready(ApplicationReadyEvent event){
System.out.println("SpringContextEventHandler ready执行..");
}
}
当我们修改application.properties中spring.profiles.active为不同值时,@Value("${app.myname}")所注入的值也不同。
二、使用@Profile("xxx")指定bean在特定的profile环境中创建
@Profile注解可以标记在任何被标记了@Configuration或@Component的java配置类声明或方法声明上。
如,我们开发环境、测试环境、生产环境中的android app版本信息不同,可以配置3个bean,分别指定不同的profile 。
AndroidAppConfiguration.java
package com.tingcream.springWeb.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import com.tingcream.springWeb.model.AndroidApp;
/**
* android app版本 对象配置
* @author jelly
*
*/
@Configuration
public class AndroidAppConfiguration {
@Bean
@Profile("dev")
public AndroidApp devAndroidApp(){
System.out.println("dev androidApp对象创建");
return new AndroidApp("我的e家掌上app", "v2.1.0", "2012-09-20", "开发环境,app描述信息");
}
@Bean
@Profile("test")
public AndroidApp testAndroidApp(){
System.out.println("test androidApp对象创建");
return new AndroidApp("我的e家掌上app", "v2.0.0", "2012-09-20", "测试环境,app描述信息");
}
@Bean
@Profile("prod")
public AndroidApp prodAndroidApp(){
System.out.println("prod androidApp对象创建");
return new AndroidApp("我的e家掌上app", "v1.5.0", "2012-09-20", "生产环境,app描述信息");
}
}
AndroidApp.java
package com.tingcream.springWeb.model;
public class AndroidApp {
private String name;
private String version;
private String publishDate;
private String describe;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPublishDate() {
return publishDate;
}
public void setPublishDate(String publishDate) {
this.publishDate = publishDate;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
public AndroidApp() {
super();
}
public AndroidApp(String name, String version, String publishDate,
String describe) {
super();
this.name = name;
this.version = version;
this.publishDate = publishDate;
this.describe = describe;
}
@Override
public String toString() {
return "AndroidApp [name=" + name + ", version=" + version
+ ", publishDate=" + publishDate + ", describe=" + describe
+ "]";
}
}
SpringContextEventHandler.java
package com.tingcream.springWeb.spring.eventListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import com.tingcream.springWeb.common.SpringContextHelper;
import com.tingcream.springWeb.model.AndroidApp;
import com.tingcream.springWeb.spring.event.MyAppEvent;
@Component
public class SpringContextEventHandler {
@Value("${app.myname}")
private String myname;
@Autowired
private AndroidApp androidApp;//注入androidApp版本对象
@EventListener
public void stopped(ContextStoppedEvent event){
System.out.println("SpringContextEventHandler stopped执行");
}
@EventListener
public void started(ContextStartedEvent event){
System.out.println("SpringContextEventHandler started执行");
}
@EventListener
public void refreshed(ContextRefreshedEvent event){
System.out.println("SpringContextEventHandler refreshed执行");
System.out.println("myname:"+myname);//打印@value注入的值
System.out.println(androidApp);//打印注入的android对象,根据指定的profile不同(dev、test、prod)打印的内容也不同
SpringContextHelper.getApplicationContext().publishEvent(new MyAppEvent("这是一段事件消息"));
}
@EventListener
public void closed(ContextClosedEvent event){
System.out.println("SpringContextEventHandler closed执行");
}
// ready
@EventListener
public void ready(ApplicationReadyEvent event){
System.out.println("SpringContextEventHandler ready执行..");
}
}
当我们修改application.properties配置文件中spring.profiles.active的值为不同值时,容器中使用@Autowire 注入的AndroidApp对象也不同。
---------
当然,@Profile 注解也可以标记在类上,如我们在代码中配置三个环境特有的配置:DevConfiguration、TestConfiguration、ProdConfiguration
DevConfiguration.java
package com.tingcream.springWeb.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import com.tingcream.springWeb.model.AndroidApp;
/**
* dev profile 特有配置
* @author jelly
*
*/
@Configuration
@Profile("dev")
public class DevConfiguration {
@Bean
public AndroidApp androidApp(){
System.out.println("dev androidApp对象创建");
return new AndroidApp("我的e家掌上app", "v2.1.0", "2012-09-20", "开发环境,app描述信息");
}
}
TestConfiguration.java
package com.tingcream.springWeb.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import com.tingcream.springWeb.model.AndroidApp;
/**
* test profile 特有配置
* @author jelly
*
*/
@Configuration
@Profile("test")
public class TestConfiguration {
@Bean
public AndroidApp androidApp(){
System.out.println("test androidApp对象创建");
return new AndroidApp("我的e家掌上app", "v2.0.0", "2012-09-20", "测试环境,app描述信息");
}
}
ProdConfiguration.java
package com.tingcream.springWeb.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import com.tingcream.springWeb.model.AndroidApp;
/**
* prod profile 特有配置
* @author jelly
*
*/
@Configuration
@Profile("prod")
public class ProductionConfiguration {
@Bean
public AndroidApp androidApp(){
System.out.println("prod androidApp对象创建");
return new AndroidApp("我的e家掌上app", "v1.5.0", "2012-09-20", "生产环境,app描述信息");
}
}
--------
除了在配置文件可指定激活哪个profile,我们也可以通过VM参数或程序参数在程序运行时手动指定, 如:
配置文件 spring.profiles.active=test
VM 参数 -Dspring.profiles.active=test
程序参数 --spring.profiles.active=test