Spring - Profile

标签:翻译 Spring
原文地址: https://www.baeldung.com/spring-profiles

更多Spring实战内容,请参考Spring - 实战指南

1. 概述

这篇文章将阐述怎么在Spring中使用Profile

从Spring 3.1开始,我们能够将bean映射到不同的profile上,如dev, test, prod等。

我们也能够根据环境(environment)来激活不同的profile,从而加载我们需要的bean。

2. 在Bean上使用@Profile

我们先从简单的例子开始,看看怎么把bean绑定到不同的profile上。

使用@Profile注解,我们可以将bean绑定到指定的profile上。这个注解支持绑定一个或多个profile。

试想这样一个场景:我们有一个bean,只在开发环境需要,线上环境不需要。那么我们可以通过注解将这个bean绑定到dev profile上。这样,这个bean只会存在于开发环境,而在其他环境中不会被加载。如下所示:

@Component
@Profile("dev")
public class DevDatasourceConfig

上面的写法是指绑定bean到dev profile。如果想绑定bean到除dev以外的profile呢。可以使用NOT操作符。如下所示:

@Component
@Profile("!dev")
public class DevDatasourceConfig

译者注:
@Profile的声明如下:

public @interface Profile {
   String[] value();
}

value是个数组,支持多个值。绑定多个profile,如下所示:

@Profile(value = {"dev", "test"})

3. 在XML中声明Profile

除了使用@Profile注解,还可以在XML中绑定profile。

<bean>标签有个profiles属性。多个profile之间使用逗号分隔:

profile还是profiles???

<beans profile="dev">
    <bean id="devDatasourceConfig"
      class="org.baeldung.profiles.DevDatasourceConfig" />
</beans>

4. 设置profile

上面只是将bean和profile进行了绑定,下一步需要设置和激活profile,才能使不同的bean被注册到容器中。方法有很多种,下面是一些例子:

4.1 使用WebApplicationInitializer interface

这是一种编程的方式(与之对应是配置方式)

在web应用中,WebApplicationInitializer可以被用来配置ServletContext

译者注:
WebApplicationInitializer在spring-web中

方法如下:

@Configuration
public class MyWebApplicationInitializer 
  implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
  
        servletContext.setInitParameter(
          "spring.profiles.active", "dev");
    }
}

译者注:
这种方式,直接把要绑定的profile硬编码到代码中,是非常不优雅,也不方便的。

4.2 使用ConfigurableEnvironment

你也可以直接在环境中设置profile:

@Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");

译者注:
问题同4.1

4.3 在web.xml中配置

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

译者注:
问题同4.1,4.2。 本人不赞成任何硬编码的方式

4.4 通过JVM参数设置

profile的名字还可以通过JVM参数的方式设置。在启动的时候,添加类似如下参数:

-Dspring.profiles.active=dev

译者注:
java -jar xxx.jar -Dspring.profiles.active=dev

4.5 通过环境变量设置

通过设置环境变量,也是可以的:

export spring_profiles_active=dev

4.6 Maven Profile

Spring profile也可以结合maven profile使用,通过设置spring.profiles.active属性:

<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>

同时,还需要在application.properties(如果使用spring boot的话)中添加如下设置:

spring.profiles.active=@spring.profiles.active@

另外,还需要再pom.xml文件中添加如下配置:

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    ...
</build>

译者注:
pom.xml中添加的配置,意思是开启占位符替换。可参考:Maven Filtering

结合使用maven profile后,就可以在打包的时候激活某个profile:

mvn clean package -Pprod

译者注:
个人认为,结合maven profile的这种办法,灵活度最高,也最方便,推荐。

4.7 Test中使用@ActiveProfiles

在test时,如何指定profile呢?也很简单,通过@ActiveProfiles注解就可以了。

@ActiveProfiles("dev")

5. 默认profile

如果不指定任何profile,那么这个bean就属于default profile

当没有任何profile被激活时,spring也支持设置默认profile。就是通过spring.profiles.default参数。

6. 获取被激活的profile

一旦profile被激活,我们就可以通过Environment,在运行时获取这些profile的信息:

public class ProfileManager {
    @Autowired
    Environment environment;
 
    public void getActiveProfiles() {
        for (final String profileName : environment.getActiveProfiles()) {
            System.out.println("Currently active profile - " + profileName);
        }   
    }
}

7. 使用Profile的例子

理论总是抽象的,下面我们通过一些例子来深入理解。

试想这样一个场景:我们要分别针对开发环境和线上环境,对datasource进行设置。我们先创建一个DatasourceConfig接口。这个接口需要在两个环境中都被实现。

public interface DatasourceConfig {
    public void setup();
}

开发环境的实现:

@Component
@Profile("dev")
public class DevDatasourceConfig implements DatasourceConfig {
    @Override
    public void setup() {
        System.out.println("Setting up datasource for DEV environment. ");
    }
}

线上环境的实现:

@Component
@Profile("production")
public class ProductionDatasourceConfig implements DatasourceConfig {
    @Override
    public void setup() {
       System.out.println("Setting up datasource for PRODUCTION environment. ");
    }
}

下面我们写个单元测试,并注入DatasourceConfig。那么我们通过设置不同的profile,就会分别注入DevDatasourceConfig bean和ProductionDatasourceConfig bean。

public class SpringProfilesTest {
    @Autowired
    DatasourceConfig datasourceConfig;
 
    public void setupDatasource() {
        datasourceConfig.setup();
    }
}

dev profile被激活的时候,会有如下输出:

Setting up datasource for DEV environment.

8. 在Spring Boot中使用Profile

Spring Boot除了支持所有的profile配置,还有提供一些额外功能。

spring.profiles.active的初始化可以在配置文件中设定:

spring.profiles.active=dev

当然也可以在程序中设定:

SpringApplication.setAdditionalProfiles("dev");

还可以在pom.xml文件中的spring-boot-maven-plugin中配置:

<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <profiles>
                <profile>dev</profile>
            </profiles>
        </configuration>
    </plugin>
    ...
</plugins>

用maven启动,可执行命令:

mvn spring-boot:run

但是Spring Boot带来的最重要的特性是profile-specific profiles文件,这些文件的命名方式需要遵循applications-{profile}.properties的格式。

举个例子:我们可以在开发环境和线上环境使用不同的数据库。如开发环境使用h2,线上环境使用mysql。那么,我们分别需要创建如下两个文件:

application-production.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=root

application-dev.properties

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

如果激活的profile是dev,则application-dev.properties配置文件会被自动加载。如果激活的profile是production,则application-production.properties 配置文件会被加载。

通过这种方式,我们就很容易地针对不同环境,配置不同的配置文件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容