09-Profile注解

@Profile 的作用

在不同的环境下使用不同的组件和配置,方便环境的动态切换

使用步骤

  1. 指定组件在哪个环境下生效
  2. 在 yml 文件中指定激活的环境

生效环境 = 激活环境/默认环境 + 包含环境(include)

环境分组

使用group来将多个环境定义成一个组,例如

spring:
  profiles:
    active: my-profile
    # 将多个环境定义成一个组
    # 鼠标放上去可以看到group的类型, 根据类型来进行格式的配置
    group:
      my-profile:
        - test
        - dev
      your-profile:
        - test
        - prod

配置文件的 Profile 功能

以 dev 环境的配置文件为例,为 application.yml 或 application.properties 添加上后缀,构成 application-dev.yml 或 application-dev.properties。

另外,对于 spring.profiles 配置项,只能够在 application.yml(基础配置文件)中配置,在诸如 application-dev.yml 中对 profile 相关的配置不会生效。基础配置文件在任何一个环境下都会生效,类似 default,但是优先级比较低。

如果环境组中两个环境的配置冲突,那么会按顺序进行覆盖,例如上面的情况下,如果 dev 环境和 test 环境中的 server.port 配置项发生冲突,那么以后面的为主,即生效的是 dev 环境。

application-test.yml

server:
  port: 8081

application-dev.yml

server:
  port: 8082

测试 @Profile

pom 依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.11</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

Bean 对象

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProfileBean {
    private Integer id;
    private String name;
}

Configuration 配置类

import org.example.bean.ProfileBean;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.util.StringValueResolver;

@Configuration
@PropertySource("classpath:my-profile.properties")
public class ProfileConfig implements EmbeddedValueResolverAware {
    // TODO: 为什么这里不可以通过@Autowired来注入
    private StringValueResolver valueResolver;

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
    }


    // 通过Environment来获取环境变量和配置文件中的值
    @Profile("test")
    @Bean
    ProfileBean profileBeanTest(Environment environment) {
        String id = environment.getProperty("profiles.test.id");
        String name = environment.getProperty("profiles.test.name");
        System.out.println("id = " + id);
        System.out.println("name = " + name);
        return new ProfileBean(Integer.parseInt(id), name);
    }


    /**
     * dev环境才注入组件
     */
    @Profile("dev")
    @Bean
    ProfileBean profileBeanDev() {
        String id = valueResolver.resolveStringValue("${profiles.dev.id}");
        String name = valueResolver.resolveStringValue("${profiles.dev.name}");
        return new ProfileBean(Integer.parseInt(id), name);
    }

    @Profile("prod")
    @Bean
    ProfileBean profileBeanProd() {
        String id = valueResolver.resolveStringValue("${profiles.prod.id}");
        String name = valueResolver.resolveStringValue("${profiles.prod.name}");
        return new ProfileBean(Integer.parseInt(id), name);
    }

}

SpringBootTest 测试类

import org.example.bean.ProfileBean;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

@SpringBootTest
public class SpringApplicationMainTest {
    @Autowired
    ApplicationContext context;

    @Test
    public void profileTest() {
        String[] names = context.getBeanNamesForType(ProfileBean.class);
        for (String name : names) {
            ProfileBean profileBean = context.getBean(name, ProfileBean.class);
            System.out.println(profileBean);
        }
    }
}

properties 文件

@PropertySource 注解只对 properties 文件有效,对 yml 类型文件无效

profiles.test.id=1
profiles.test.name=test
profiles.dev.id=2
profiles.dev.name=dev
profiles.prod.id=3
profiles.prod.name=prod

   转载规则


《09-Profile注解》 熊水斌 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
04-Conditional注解 04-Conditional注解
@Conditional条件注入不使用条件注入前package com.xiong.config; import com.xiong.bean.Person; import org.springframework.beans.factor
2023-05-13
下一篇 
多版本并发控制(MVCC) 多版本并发控制(MVCC)
多版本并发控制(MVCC)前置知识:事务并发问题脏读事务A中读取到事务B中未提交的数据。具体来说,在t1时刻,事务A中读取到事务B中未提交的数据,并将该数据用于计算得到一个结果值;而在t2时刻,事务B执行回滚,那么事务A中得到的结果值就没有
2023-05-11
  目录