@profile注解 使用说明:
spring3.2之前 @Profile注解用在类上
spring3.2 之后 @Profile注解用在 方法上
另外一种说法
在项目运行中,包括多种环境,例如线上环境prod(product)、开发环境dev(development)、测试环境test、提测环境qa、单元测试unitest等等。不同的环境需要进行不同的配置,从而在不同的场景中跑我们的程序。例如prod环境和dev环境通常需要连接不同的数据库、需要配置不同的日志输出配置。还有一些类和方法,在不同的环境下有不同的实现方式。
Spring Boot 对此提供了支持,一方面是注解@Profile,另一方面还有多资源配置文件。
@profile
注解的作用是指定类、方法、注解上,在特定的 Profile 环境生效,任何@Component
或@Configuration
注解的类都可以使用@Profile
注解。在使用DI来依赖注入的时候,能够根据@profile
标明的环境,将注入符合当前运行环境的相应的bean。
使用要求:
@Component和@Configuration
的类上作为一个类型注解使用@profile
@Profile
中需要指定一个字符串,约定生效的环境@Profile
作为元注解,用于组成自定义构造型注解@Profile
作为任何@Bean方法的方法级注解@Profile
的使用位置@Prifile
修饰类@Configuration
@Profile("prod")
public class JndiDataConfig {
@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
@Profile
修饰方法@Configuration
public class AppConfig {
@Bean("dataSource")
@Profile("dev")
public DataSource standaloneDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
@Bean("dataSource")
@Profile("prod")
public DataSource jndiDataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
@Profile
修饰注解@Profile
注解支持定义在其他注解之上,以创建自定义场景注解。这样就创建了一个@Dev
注解,该注解可以标识bean使用于@Dev
这个场景。后续就不再需要使用@Profile("dev")
的方式,这样即可以简化代码。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("dev")
public @interface Dev{
}
实际使用中,注解中标示了prod、test、dev等多个环境,运行时使用哪个profile由spring.profiles.active控制,以下说明常见的几种方式。
确定当前使用的是哪个环境,这边环境的值与application-prod.properties中-后面的值对应,这是SpringBoot约定好的。
在resources/application.properties中添加下面的配置。需要注意的是,spring.profiles.active的取值应该与@Profile
注解中的标示保持一致。
spring.profiles.active=dev
除此之外,同理还可以在resources/application.yml中配置,效果是一样的:
spring:
profiles:
active: dev
注意:
spring.profiles.active 激活方式 ,如果 spring.profiles.active 未配置,则使用spring.profiles.default激活方式。如果前面都没有配置,就会加载没有定义在profile中的bean
SpringBoot默认会加载并读取该配置,当发现为profile=dev时,会同时关联加载application-dev.properties这个配置。这种方式非常简单,可以实现对不同环境采用单独的配置文件进行隔离。
在打包后运行的时候,添加参数:
(1)java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
(2)java -jar application.jar -Dspring.profiles.active=dev
(3)java -jar -Dspring.profiles.active=prod *.jar
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</context-param>
<servlet>
<servlet-name>zszxzServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>zszxzServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
@RunWith(SpringJUnit4ClassRunner.class)//创建spring应用上下文
@ContextConfiguration(classes= DataSourceConfig.class)//加载配置类
@ActiveProfiles("dev")
public class ProfileTest {
@Autowired
private DataSource dataSource;
@Test
public void sheetTest(){
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
List<String> query = jdbc.query("select * from customer", new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong("id") + ":" + rs.getString("customer_name");
}
});
// [19:知识追寻者, 20:知识追寻者, 21:知识追寻者, 22:知识追寻者, 23:知识追寻者]
System.out.println(query);
}
}
方式1:直接指定环境变量来激活 profile:
System.setProperty("spring.profiles.active", "test");
方式2:在 Spring 容器中激活 profile:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();
方式3:实现WebApplicationInitializer接口
在Web应用程序中,通过WebApplicationInitializer可以对当前的ServletContext进行配置。
如下,通过注入spring.profiles.active变量可以为Spring上下文指定当前的 profile:
@Configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter(
"spring.profiles.active", "dev");
}
}
方式4:使用 ConfigurableEnvironment
ConfigurableEnvironment 这个Bean封装了当前环境的配置信息,你可以在启动应用前进行设定操作:
SpringApplication application = new SpringApplication(MyApplication.class);
//设置environment中的profiler
ConfigurableEnvironment environment = new StandardEnvironment();
environment.setActiveProfiles("dev","join_dev");
application.setEnvironment(environment);
application.run(args)
方式5:SpringApplication.setAdditionalProfiles
SpringApplication这个类还提供了setAdditionalProfiles方法,用来让我们实现"附加"式的profile。
这些profile会同时被启用,而不是替换原来的active profile,如下:
SpringApplication application = new SpringApplication(MyApplication.class);
application.setAdditionalProfiles("new_dev");
注意:
这种方式可以实现无条件的启用profile,优先级是最高的。
当然,还可以通过设定spring.profiles.include来达到同样的目的。
在Unix/Linux环境中,可以通过环境变量注入profile的值:
export spring_profiles_active=dev
java -jar application.jar
Maven本身也提供了Profile的功能,可以通过Maven的Profile配置来指定Spring的Profile。
这种做法稍微有点复杂,需要先在pom.xml中设定不同的 maven profile,如下:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
</profile>
</profiles>
这里,分别声明了dev和prod两个profile,每个profile都包含了一个spring.profiles.active属性,这个属性用来注入到 Spring中的profile入参。
在SpringBoot的配置文件application.properties中,需要替换为这个maven传入的property:
使用Maven的属性进行替换
spring.profiles.active=@spring.profiles.active@
接下来,需要让Maven在打包时能将application.properties进行过滤处理,同时替换掉变量,需编辑pom.xml如下:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
这里定义了filtering=true,因此Resource打包插件会对配置文件执行过滤。
如果你的项目pom定义继承自 spring-boot-starter-parent,那么可以不需要配置这个filter
最后,在maven打包时指定参数如下:
mvn clean package -P prod
(1)、SpringApplication.setAdditionalProfiles
(2)、ConfigurableEnvironment、@ActiveProfiles
(3)、Web.xml的 context-param
(4)、WebApplicationInitializer
(5)、JVM 启动参数
(6)、环境变量
(7)、Maven profile、application.properties
从上至下,优先级从高到低排列。
其中,Maven profile与配置文件的方式相同,环境变量以及JVM启动参数会覆盖配置文件的内容。
1和2则属于进程内的控制逻辑,优先级更高。
如果在启动SpringBoot应用前对当前ConfigurableEnvironment对象注入了profile,则会优先使用这个参数, ActiveProfiles用于测试环境,其原理与此类似。
SpringApplication.setAdditionalProfiles则是无论如何都会附加的profile,优先级最高。
另外profile表达式支持以下运算符:
(1)、 ! - 逻辑非
(2) 、& - 逻辑并
(3).、| - 逻辑或
@Profile可接受一个或者多个参数,例如:
@Profile({"test","prod"})
@Configuration
public class WebConfig{
@Bean
public Queue hello(){
return new Queue("hello");
}
@Profile("receiver")
@Bean
public Receiver receiver(){
return new Receiver();
}
@Profile("dev")
@Bean
public DevDemo dev(){
return new DevDemo ();
}
当 spring.profiles.active=prod,dev 时,该配置类生效,且第一个@Bean和第三个@Bean生效
如果spring.profiles.active=prod ,则该配置文件生效,第一个@Bean生效
如果spring.profiles.active=dev ,该配置文件未生效,所以下面的@Bean都不会生效
如此,当我们的项目需要运行在不同环境,特异化配置又比较多,该注解的优势是相当明显的!
/**
* @Author lsc
* spring3.2之前 @Profile注解用在类上
* spring3.2 之后 @Profile注解用在 方法上
*
*/
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
System.out.println(" dev DataSource !!");
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
basicDataSource.setUrl("jdbc:mysql://localhost:3308/zszxz");
basicDataSource.setUsername("root");
basicDataSource.setPassword("1234");
return basicDataSource;
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
System.out.println(" prod DataSource !!");
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
basicDataSource.setUrl("jdbc:mysql://localhost:3306/zszxz");
basicDataSource.setUsername("root");
basicDataSource.setPassword("1234");
return basicDataSource;
}
}
如果你是在xml中配置,示例如下
<beans profile="dev">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/zszxzb"
p:username="root"
p:password="1234"/>
</beans>
<beans profile="prod">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/zszxzb"
p:username="root"
p:password="1234"/>
</beans>
鸣谢:
https://blog.csdn.net/loongkingwhat/article/details/105745303
https://www.jianshu.com/p/75de79fba705
https://www.cnblogs.com/huahua-test/p/11576907.html