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个属性:

  1. spring.profiles.active
  2. 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版)》

最新文章

  1. iOS Salesforce SDK 小知识
  2. 汇编学习(三)&mdash;&mdash;汇编语言程序入门
  3. sql server 使用函数辅助查询
  4. 餐厅到店点餐系统app燃尽图
  5. 【转载】jQuery插件开发精品教程,让你的jQuery提升一个台阶
  6. mysql 查询开销 sending data
  7. C#: .net序列化及反序列化 [XmlElement(“节点名称”)]
  8. java动态代理与老式AOP实现
  9. BZOJ 1588 营业额统计 Splay
  10. Xcode 3.2.5免证书开发调试
  11. Qunit 和 jsCoverage使用方法
  12. scrapy setting 备注
  13. 快速用Markdown排版一篇文章
  14. [物理学与PDEs]第1章习题8 磁场分布 $\ra$ 电流分布
  15. 将字符串向hdfs中写入,出现中文乱码!
  16. html5dom2
  17. NEWBE CRALWER 产品需求文档
  18. ubuntu运行命令tee显示和保存为log
  19. vue的双向数据绑定原理
  20. 【Hibernate学习笔记-5.1】使用@Transient修饰不想持久保存的属性

热门文章

  1. 手写 Spring
  2. 个人永久性免费-Excel催化剂功能第91波-地图数据挖宝之行政区域信息实时下载(含经纬度)
  3. 个人永久性免费-Excel催化剂功能第20波-Excel与Sqlserver零门槛交互-数据上传篇
  4. hdu6396 Swordsman(贪心)
  5. 跟着大彬读源码 - Redis 6 - 对象和数据类型(下)
  6. Atom实用插件
  7. Tomcat(Windows)
  8. 如何挑选node docker镜像
  9. Linux目录文件
  10. RabbitMQ(三):RabbitMQ与Spring Boot简单整合