Spring Profile使用讲解
1. 使用场景
在日常的开发工作中,我们经常需要将程序部署到不同的环境,比如Dev开发环境,QA测试环境,Prod生产环境,这些环境下的一些配置肯定是不一样的,比如数据库配置,Redis配置,RabbitMQ配置。
如果每次切换发布环境,都需要修改配置重新构建的话,那对程序员来说将是噩梦,针对这种场景,Spring提供了@Profile注解来实现按照不同的环境装配不同的bean,进而实现程序只需构建一次,但可以部署到多个环境。
2. 配置profile bean
为了更好的理解,我们通过具体的代码示例来理解下Spring profile的使用方法,这里我们以数据库配置为例。
说明:本篇博客的重点是讲解@Profile注解的使用,数据库的操作只是辅助理解@Profile,因此不会讲解的太详细
假设我们有3套环境(Dev,QA,Prod),这3套环境的数据库都使用的是mysql,但是其地址,用户名,密码都不一样,那么在Java配置中,该如何声明这些bean呢?
2.1 Java配置中配置profile bean
首先需要了解的是,@Profile
注解是从Spring 3.1版本中开始引入的,并且在这个版本中,@Profile
注解只能在类级别上使用。
因此我们可以按照环境分别创建数据库配置,如下所示:
Dev环境下的数据库配置:
package chapter03.profile; import org.apache.commons.dbcp2.BasicDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; @Configuration @Profile("dev") public class DevDataSourceConfig { @Bean public DataSource devDataSource() { System.out.println("This is dev DataSource"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3306/mybatis_action_db"); basicDataSource.setUsername("dev"); basicDataSource.setPassword("dev"); return basicDataSource; } }
使用上述代码需要在pom.xml中添加如下依赖:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.7.0</version> </dependency>
注意事项:如果类级别上使用了@Profile("dev"),那么该类中的所有bean都会在profile为dev时创建。
QA环境下的数据库配置:
package chapter03.profile; import org.apache.commons.dbcp2.BasicDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; @Configuration @Profile("qa") public class QADataSourceConfig { @Bean public DataSource qaDataSource() { System.out.println("This is qa DataSource"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3307/mybatis_action_db"); basicDataSource.setUsername("qa"); basicDataSource.setPassword("qa"); return basicDataSource; } }
Prod环境下的数据库配置:
package chapter03.profile; import org.apache.commons.dbcp2.BasicDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; @Configuration @Profile("prod") public class ProdDataSourceConfig { @Bean public DataSource prodDataSource() { System.out.println("This is prod DataSource"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3308/mybatis_action_db"); basicDataSource.setUsername("prod"); basicDataSource.setPassword("prod"); return basicDataSource; } }
不过从Spring 3.2开始,@Profile
注解可以与@Bean
注解一起在方法级别上使用。
这也就使得我们可以将刚刚的3个配置类合并成1个配置类(推荐该方式),如下所示:
package chapter03.profile; import org.apache.commons.dbcp2.BasicDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; @Configuration public class DataSourceConfig { @Bean @Profile("dev") public DataSource devDataSource() { System.out.println("This is dev DataSource"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3306/mybatis_action_db"); basicDataSource.setUsername("dev"); basicDataSource.setPassword("dev"); return basicDataSource; } @Bean @Profile("qa") public DataSource qaDataSource() { System.out.println("This is qa DataSource"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3307/mybatis_action_db"); basicDataSource.setUsername("qa"); basicDataSource.setPassword("qa"); return basicDataSource; } @Bean @Profile("prod") public DataSource prodDataSource() { System.out.println("This is prod DataSource"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3308/mybatis_action_db"); basicDataSource.setUsername("prod"); basicDataSource.setPassword("prod"); return basicDataSource; } }
注意事项:没有指定profile的bean始终都会创建,与激活哪个profile无关。
2.2 xml中配置profile bean
我们也可以通过<beans>
元素的profile属性,在xml中配置profile bean,如下所示:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" profile="dev"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mybatis_action_db" p:username="dev" p:password="dev"/> </beans>
可以参考该配置,分别创建qa和prod环境的profile xml文件。
不过还是推荐使用嵌套的<beans>
元素,在一个xml文件中配置好3个环境的数据源,代码如下所示:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <beans profile="dev"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mybatis_action_db" p:username="dev" p:password="dev"/> </beans> <beans profile="qa"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3307/mybatis_action_db" p:username="qa" p:password="qa"/> </beans> <beans profile="prod"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3308/mybatis_action_db" p:username="prod" p:password="prod"/> </beans> </beans>
3. 激活profile
截止目前,我们按照环境的维度创建了3个bean,但实际运行时,只会创建1个bean,具体创建哪个bean取决于处于激活状态的是哪个profile。
那么,我们该如何激活某个profile呢?
Spring在确定激活哪个profile时,需要依赖2个属性:
- spring.profiles.active
- spring.profiles.default
spring.profiles.active
的优先级比spring.profiles.default
高,即如果没有配置spring.profiles.active
,就使用spring.profiles.default
配置的值,如果配置了spring.profiles.active
,就不会再使用spring.profiles.default
配置的值。
如果两者都没有配置,就只会创建那些没有定义profile的bean。
Web应用中,在web.xml中设置spring.profiles.active
的代码如下所示:
<context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param>
也可以使用代码方式激活:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.getEnvironment().setActiveProfiles("dev");
4. 单元测试
新建Main类,在其main()方法中添加如下测试代码:
package chapter03.profile; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.getEnvironment().setActiveProfiles("dev"); context.register(DataSourceConfig.class); context.refresh(); context.close(); } }
输出结果如下所示:
This is dev DataSource
如果将代码修改为context.getEnvironment().setActiveProfiles("qa");
,输出结果为:
This is qa DataSource
如果将代码修改为context.getEnvironment().setActiveProfiles("prod");
,输出结果为:
This is prod DataSource
5. 源码及参考
源码地址:https://github.com/zwwhnly/spring-action.git,欢迎下载。
汪云飞《Java EE开发的颠覆者:Spring Boot实战》
Craig Walls 《Spring实战(第4版)》
相关文章
- 解决IDEA使用Spring Initializr创建项目时,无法连接到https://start.spring.io的问题
- Sping框架的IOC特性 悲观锁、乐观锁 Spring的AOP特性
- 10 -- 深入使用Spring -- 5... 实现任务的自动调度
- Spring Boot 3.0.1-SNAPSHOT 正式发布,这份升级指南必须收藏
- spring mvc有哪些组件?
- [转]Spring IOC 一——容器装配Bean的简单使用
- Spring @Conditional注解 详细讲解及示例[转载]
- Spring-boot-Java工程添加prometheus监控(actuator+micrometer和simpleclient+micrometer两种方案)
- Spring Boot面试讲解
- Spring Cloud Gateway核心概念和工作原理
- Spring基于注解的IOC初始化(七)
- Spring Boot 测试
- Spring Boot中使用@Async的时候,千万别忘了线程池的配置!
- Java回顾之Spring基础
- springJdbc like模糊查询,Spring namedParameterJdbcTemplate like查询
- spring计划任务,springMvc计划任务,Spring@Scheduled,spring定时任务
- Spring boot异常统一处理方法:@ControllerAdvice注解的使用、全局异常捕获、自定义异常捕获
- spring的设计模式
- 在Spring Boot中使用内存数据库
- spring框架漏洞整理(Spring Boot Actuator命令执行漏洞)
- spring框架漏洞整理(Spring Framework漏洞)
- 【Spring Cloud】Ribbon负载均衡原理与实战(源码级讲解)
- maven初始搭建一个基础项目(spring mvc+spring+jdbc mysql+jstl)
- Spring_讲解
- 【转】Spring学习---为什么要用spring,springMVC
- mvn打包spring工程成jar时报Unable to locate Spring NamespaceHandler for XML schema namespace错误解决办法
- 最近无意中看到一个讲解spring mvc的系列,从源码的角度讲解,特记录下来,供以后反复学习
- Spring Security Java Config Preview--官方
- spring之DelegatingFilterProxy
- spring mvc DispatcherServlet详解之interceptor和filter的区别
- 曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成
- Spring整合CXF之添加拦截器