有时候咱们有两个配置文件, 一个是dev环境的, 一个是线上product环境的, 在开发的时候, 启动加载dev配置文件, 上线后启动应用product的配置; 这里就能够用到@Profile的性能;
其原理就是在上下文启动的时候, 通过扭转一个环境参数(-Dspring.profiles.active=xxx
)的值, 让spring去抉择加载和初始化对应的profile;
举例: 咱们有两套数据源配置: dev
和 product
; 配置区别大体如下:
- 配置文件:
src\main\resources\db.properties
dev.mysql.url = jdbc:mysql://127.0.0.1/dev
dev.mysql.username = niewj
dev.mysql.password = 123456
dev.mysql.validationQuery = SELECT 1
#-----------------
product.mysql.url = jdbc:mysql://niewj.com/product
product.mysql.username = root
product.mysql.password = 654321
product.mysql.validationQuery = SELECT 1
- 配置注解文件:
ProfilesDatasourceConfig.java
package com.niewj.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:/db.properties")
public class ProfilesDatasourceConfig {
/**
* product 配置
*/
@Value("${product.mysql.url}")
private String urlProduct;
@Value("${product.mysql.username}")
private String usernameProduct;
@Value("${product.mysql.password}")
private String passwordProduct;
/**
* dev 配置
*/
@Value("${dev.mysql.url}")
private String urlDev;
@Value("${dev.mysql.username}")
private String usernameDev;
@Value("${dev.mysql.password}")
private String passwordDev;
/**
* 其余通用配置
*/
@Value("${dev.mysql.validationQuery}")
private String validationQuery = "SELECT 1";
@Profile("dev")
@Bean
public DruidDataSource dataSourceDev(){
DruidDataSource ds = new DruidDataSource();
ds.setUrl(urlDev);
ds.setUsername(usernameDev);
ds.setPassword(passwordDev);
ds.setValidationQuery(validationQuery);
System.out.println("初始化-dev-druidDataSource");
return ds;
}
@Profile("product")
@Bean
public DruidDataSource dataSourceProduct(){
DruidDataSource ds = new DruidDataSource();
ds.setUrl(urlProduct);
ds.setUsername(usernameProduct);
ds.setPassword(passwordProduct);
ds.setValidationQuery(validationQuery);
System.out.println("初始化-product-druidDataSource");
return ds;
}
}
- 测试用例:
src\test\java\com\niewj\ProfileTest.java
package com.niewj;
import com.alibaba.druid.pool.DruidDataSource;
import com.niewj.config.ProfilesDatasourceConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.stream.Stream;
/**
* spring profile测试
*/
public class ProfileTest {
@Test
public void testProfile() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ProfilesDatasourceConfig.class);
ctx.getEnvironment().setActiveProfiles("product"); // 1
// ctx.getEnvironment().setActiveProfiles("dev"); // 2
ctx.refresh();
// 打印spring容器中的 BeanDefinition
Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));
System.out.println("=============================");
DruidDataSource ds = null;
if ((ds = ctx.getBean(DruidDataSource.class)) != null) {
System.out.println(ds);
}
ctx.close();
}
}
这里有两种形式能够实现调用:
1. 批改spring上下文的Environment参数
结构器初始化时不传入加载配置类; 而是初始化后, 上下文手动注册配置类, 而后批改active profiles, 最初refresh上下文;
其实传入配置类的结构器的源码如下: 咱们如果应用它, 就无奈批改环境参数并refresh了, 所以注册的事件咱们本人来干!
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
咱们这么操作, 输入如下:
output: 可见是加载了 product
的profile; 同样 换了 dev
亦然!
初始化-product-druidDataSource
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
profilesDatasourceConfig
dataSourceProduct
=============================
{
CreateTime:"2020-07-17 17:11:46",
ActiveCount:0,
PoolingCount:0,
CreateCount:0,
DestroyCount:0,
CloseCount:0,
ConnectCount:0,
Connections:[
]
}
七月 17, 2020 5:11:46 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-0} closing ...
2. 执行加参数-Dspring.profiles.active=product
应用结构器注册配置类, 而后执行的时加参数-Dspring.profiles.active=product
来触发调用, 达到目标;
(1). 结构器初始化加载配置类:
@Test
public void testProfileConstructure() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ProfilesDatasourceConfig.class);
// 打印spring容器中的 BeanDefinition
Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));
System.out.println("=============================");
DruidDataSource ds = null;
if ((ds = ctx.getBean(DruidDataSource.class)) != null) {
System.out.println(ds);
}
ctx.close();
}
(2). 执行时加参数 -Dspring.profiles.active=product
, 这种形式 输入也和下面一样的, output 略去
3. 小结:
(1). deault
: 多个 @Profile("dev") @Profile("product")
, 如果执行时没有手动加参数: -Dspring.profiles.active=xxx
默认只会寻找@Profile("default")
的; 没有的话, 就都不会在容器中初始化;
(2). 如果@Profile("dev")
是在配置类上注解的, 类下所有的操作只有在匹配到执行时 -Dspring.profiles.active=dev
时, 才会初始化, 否则, 甚至连配置类自身都不会初始化注册到容器;
(3). 顺着(2)的阐明, 如果执行时-Dspring.profiles.active=dev
, 类上的注解也是@Profile("dev")
, 此配置类中没有@Profile
注解的 @Bean
办法都会失常初始化注册到容器; 只有不匹配的@Profile("xxx")
不会注册;
(4). ctx.getEnvironment().setActiveProfiles("product")
,能够设置多个: ctx.getEnvironment().setActiveProfiles("product", "dev")
发表回复