前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解 @Profile 巧妙切换Spring的环境变量

深入理解 @Profile 巧妙切换Spring的环境变量

作者头像
码农架构
发布2021-11-11 10:41:49
1.1K0
发布2021-11-11 10:41:49
举报
文章被收录于专栏:码农架构码农架构

导读:在开发环境与生产环境使用不同的参数,可以配置两套配置文件,通过@profile来激活需要的环境。

背景


多环境集成开发中,不免会有很多配置,在容器中如果存在同一类型的多个组件,也可以使用@Profile注解标识要获取的是哪一个bean,这在不同的环境使用不同的变量的情景特别有用。例如,开发环境、测试环境、生产环境使用不同的数据源,在不改变代码的情况下,可以使用这个注解来切换要连接的数据库。

工作原理


多环境集成开发中,不免会有很多配置,在容器中如果存在同一类型的多个组件,也可以使用@Profile注解标识要获取的是哪一个

当一个或多个指定的配置文件处于活动状态时,表示组件有资格注册。

配置文件是一个命名的逻辑分组,可以通过ConfigurableEnvironment.setActiveProfiles以编程方式激活,

也可以通过将spring.profiles.active属性设置为 JVM 系统属性、环境变量或web.xmlServlet上下文参数以声明方式激活 web应用程序。

配置文件也可以通过@ActiveProfiles注释在集成测试中以声明方式激活。

@Profile注释可以通过以下任何一种方式使用:

  • 作为任何直接或间接用@Component注释的类的类型级注释,包括@Configuration
  • 作为元注释,用于编写自定义构造型注释
  • 作为任何@Bean方法的方法级注解
▐ ⚠️注意
  • 如果一个@Configuration类标有@Profile ,所有的@Bean方法和@Import与该类相关联的注释将被忽略,除非一个或多个指定的简档是活动的。配置文件字符串可能包含简单的配置文件名称(例如"p1" )或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如"p1 & p2" 。
  • 如果省略@Profile注释,则无论哪个(如果有)配置文件处于活动状态,都会进行注册。
  • @Bean方法上使用@Profile时,可能适用一种特殊情况:在重载相同Java 方法名称的@Bean方法的情况下(类似于构造函数重载),需要在所有重载方法上一致地声明@Profile条件. 如果条件不一致,则只有重载方法中第一个声明的条件才重要。@Profile因此不能用于选择具有特定参数签名的重载方法而不是另一个方法;同一个 bean 的所有工厂方法之间的解析在创建时遵循 Spring 的构造函数解析算法。如果您想定义具有不同配置文件条件的替代 bean,请使用指向相同bean name不同 Java 方法名称。

应用实战


Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;

开发环境develop、测试环境test、生产环境master数据源:(/dev) (/test) (/master)

@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

  • 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
  • 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效

▐ 以下是在不同环境下不同的数据源组件的示例

package com.spring.config;
 
import java.beans.PropertyVetoException;
 
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
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.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
 
import com.mchange.v2.c3p0.ComboPooledDataSource;
 
/**
 * Profile:
 *   Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 * 
 * 开发环境develop、测试环境test、生产环境master
 * 数据源:(/dev) (/test) (/master)
 *
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 * 
 * 1) 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
 * 2) 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 
 */
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
 
 @Value("${db.user}")
 private String user;
 
 private String driverClass;
 
 @Profile("default")
 @Bean("test")
 public DataSource testDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
  ComboPooledDataSource dataSource = new ComboPooledDataSource();
  dataSource.setUser(user);
  dataSource.setPassword(password);
  dataSource.setDriverClass(driverClass);
  return dataSource;
 }
 
 @Profile("dev")
 @Bean("dev")
 public DataSource devDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
  ComboPooledDataSource dataSource = new ComboPooledDataSource();
  dataSource.setUser(user);
  dataSource.setPassword(password);
  dataSource.setDriverClass(driverClass);
  return dataSource;
 }
 
 @Profile("master")
 @Bean("master")
 public DataSource masterDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
  ComboPooledDataSource dataSource = new ComboPooledDataSource();
  dataSource.setUser(user);
  dataSource.setPassword(password);
  dataSource.setDriverClass(driverClass);
  return dataSource;
 }
 
 public void setEmbeddedValueResolver(StringValueResolver resolver) {
  String driverClass = resolver.resolveStringValue("${db.driverClass}");
  this.driverClass = driverClass;
 }
 
}

▐ 以下是切换数据源示例

//创建匿名容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//设置环境,其值为@Profile注解的属性值
applicationContext.getEnvironment().setActiveProfiles("test");
//注册容器类
applicationContext.register(ProfileBeanConfig.class);
//刷新容器
applicationContext.refresh();

总结


在开发环境与生产环境使用不同的参数,可以配置两套配置文件,通过@profile来激活需要的环境,但维护两套配置文件不如maven中维护一套配置文件,在pom中通过profile来修改配置文件的参数来的实惠。

也有例外,比如我在开发中调用商城接口经常不能返回我需要的数据,每次都需要mock数据,所以我写了一个mock参数的借口调用类,在开发环境中就使用这个类,测试环境与生产环境则使用正常的借口调用类,这样就不用每次开发的时候去手动改一些代码。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 工作原理
    • ▐ ⚠️注意
    • 应用实战
    • 总结
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档