springel表达式隔离不同环境的rocketmq(代码片段)

carl-zhao carl-zhao     2022-12-18     651

关键词:

项目之前使用的是 RabbitMQ 作为消息中间件用来解耦服务之间的调用,现在需要对消息中间件进行升级决定采用 RocketMQ。RocketMQ 相比 RabbitMQ 更具有优势,当然大家可以在网上查找到相关资料。这里就不在赘述了。今天主要是讲如何使用 Spring EL 表达式来隔离不同环境的 RocketMQ 的。

因为在非生产环境我们为了优化资源的效果,只部署了一套 RabbitMQ 环境。但是非生产环境有多套环境:dev(开发环境)、test(测试环境)、pre(预生产环境)。所以我们在使用 RabbitMQ 的时候用虚拟主机对于不同的环境的服务进行资源隔离。

每一个RabbitMQ服务器都能创建虚拟的消息服务器,我们称之为虚拟主机(virtual host),简称为vhost。每一个vhost本质上是一个独立的小型RabbitMQ服务器,拥有自己独立的队列、交换器以及绑定关系等待,并且它拥有自己独立的权限。

当我们使用 RocketMQ 的时候,它就没有虚拟主机这个概念,那只有另想它法了。

在使用 RocketMQ 消息队列时,我们可以使用 Topic 来隔离环境。就是在消息发送的时候 Topic 上面带上环境信息,并且在消息消费需要使用 Topic 与消费组都带上环境信息。比如,我们需要发送一个订单消息,我们假设定义一个 Topic 名为 order

  • 在开发环境(dev),消息发送方发送消息主题为: order-dev,消息消费方配置消息主题为 order-dev,然后配置消费组为 order-consumer-dev
  • 在测试环境(test),消息发送方发送消息主题为: order-test,消息消费方配置消息主题为 order-test,然后配置消费组为 order-consumer-test
  • 在预生产环境(pre),消息发送方发送消息主题为: order-pre,消息消费方配置消息主题为 order-pre,然后配置消费组为 order-consumer-pre
  • 在生产环境(pro),消息发送方发送消息主题为: order,消息消费方配置消息主题为 order,然后配置消费组为 order-consumer

在我们使用 RocketMQ 的时候通常是使用官方提供的 Spring Boot Stater 包,比如:

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>

我们在使用消息发送的时候使用 RocketMQTemplate 来进行消息发送:

rocketMQTemplate.sendAndReceive("主题", message);

这里的消息主题我们可以使用 @Value 然后通过 Spring EL 表达式来根据环境动态来生成需要发送的消息主题。

在消息消费方,我们使用 @RocketMQMessageListener 注解通过 topic 来定义需要消费的主题,consumerGroup 来定义需要消费组。这两个参数都支持 Spring EL 表达式,所以我们之前的方案是可行的。

RocketMqManager.java

public class RocketMqManager implements EnvironmentAware 

    private Environment environment;

    public String getValue(String value) 
        String profile = getProfile();
        if(isProduct(profile)) 
            return value;
         else 
            return value + "-" + profile;
        
    

    @Override
    public void setEnvironment(Environment environment) 
        this.environment = environment;
    

    private boolean isProduct(String profile) 
        return "pro".equals(profile);
    

    private String getProfile()
        String[] activeProfiles = environment.getActiveProfiles();
        if(ArrayUtils.isEmpty(activeProfiles)) 
            throw new RuntimeException();
        
        return activeProfiles[0];
    


RocketMqManager 是 RocketMQ 工具类,它会通过不同的环境来生成不同的值来满足我们上面说的资源隔离。生产环境就直接返回传入的值,否则的话就在传入的值后面添加上 "-" + 环境

Topic

@Data
public class Topic 

    @Value("#rocketMqManager.getValue('order')")
    private String topic;


Topic 类就是以我们想要通过 Spring EL 表达式根据不同的环境动态获取消息主题(ps:消息消费者组也是同样的逻辑)。这里面 Spring EL 表达式通过调用 Spring Bean 使用到了我们之前定义的工具类。

Config.java

@Configuration
public class Config 

    @Bean("rocketMqManager")
    public RocketMqManager rocketMqManager()
        return new RocketMqManager();
    

    @Bean("topic")
    public Topic topic()
        return new Topic();
    



通过 Spring Class 类型的 bean 来定义 bean 方便我们的测试。

Test.java

public class Test 

    public static void main(String[] args) 
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.getEnvironment().setActiveProfiles("dev");
        applicationContext.register(Config.class);
        applicationContext.refresh();
        Topic topic = applicationContext.getBean(Topic.class);
        System.out.println("当前 Topic 为 : " + topic.getTopic());
    


测试类,首先我们定义我们的环境是开发环境(dev),运行结果如下:

当我们修改环境为生产环境(pro),运行结果如下:

这样就达到我们隔离环境的效果了。

参考文章

spring使用spring表达式(springel)(代码片段)

  Spring还提供了更灵活的注入方式,那就是Spring表达式,实际上SpringEL远比以上注入方式强大,我们需要学习它。SpringEL拥有很多功能。  使用Bean的id来引用Bean。  •调用指定对象的方法和访问对象的属性。  •进... 查看详情

评估 SpringEL 表达式的 Spring Boot 异常

】评估SpringEL表达式的SpringBoot异常【英文标题】:SpringBootExceptionevaluatingSpringELexpression【发布时间】:2019-05-2416:09:15【问题描述】:错误4904---[nio-8080-exec-1]org.thymeleaf.TemplateEngine:[THYMELEAF][http-nio-8080-exec-1]异常处理模板“index”:模... 查看详情

springel表达式错误记录

原因暂时未知。。。。 查看详情

评估 SpringEL 表达式的异常:“#dates.format(passation.datepassation, 'dd-MMM-yyyy')”

】评估SpringEL表达式的异常:“#dates.format(passation.datepassation,\\\'dd-MMM-yyyy\\\')”【英文标题】:ExceptionevaluatingSpringELexpression:"#dates.format(passation.datepassation,\'dd-MMM-yyyy\')"评估SpringEL表达式的异常:“#dates.format 查看详情

spring学习(十三)-----spring表达式语言(springel)

...讲述了SpringExpressionLanguage——即Spring3中功能丰富强大的表达式语言,简称SpEL。SpEL是类似于OGNL和JSFEL的表达式语言,能够在运行时构建复杂表达式,存取对象属性、对象方法调用等。所有的SpEL都支持XML和Annotation两种方式,格式... 查看详情

使用springel表达式进行方法调用

原文链接:http://www.yiidian.com/spring/spring-el-method.htmlSpEL允许开发者用El运行方法函数,并且允许将方法返回值注入到属性中。一、编写Bean类TestMethod类packagecom.yiidian;/****@authorhttp://www.yiidian.com**/publicclassTestMethod{publicDoub 查看详情

深入浅出spring原理及实战「原理分析专题」从零开始教你springel表达式使用和功能分析讲解指南(上篇)(代码片段)

SpringEL表达式语言,这种语言jsp中学到的el,但是在整个spring之中其表达式语言要更加的复杂,而且支持度更加的广泛,最重要的是他可以进行方法的调用,对象的实例化,集合操作等等,但是唯一的难点就是:代码太复杂了,表达式太复杂... 查看详情

架构方案:测试场多环境逻辑隔离方案

引言随着功能的迭代和业务的增长,一套开发环境和一套测试环境往往很难满足需求。不同的功能、不同的分支代码在同一套环境测试,难免互相影响。所以看到公司往往有多套开发环境和多套测试环境,以应对这些冲突。多套... 查看详情

spring04-springel&springjdbc数据访问

...运行时查询和操作对象图的强大的动态语言,语法类似于EL表达式,具有诸如显示方法和基本字符串模板函数等特性.1.准备工作项目:spring-el2.需要导入jar包spring-expression.jarmaven项目pom文件添加:1<dependency>2<groupId>org.spr 查看详情

pycharm环境搭建

...  可以通过piplist查看已安装的模块   三、虚拟隔离环境  为什么要建虚拟隔离环境?  1、Python的工具包有很多,而且有不同的版本,各个版本之间有可能存在依赖关系!当你不小心升级了某个工具包后,会有很多... 查看详情

虚拟环境

1.介绍:  虚拟环境就是一个隔离的python环境不同的项目应该使用不同的虚拟环境,(可以使用同一个虚拟环境),虚拟环境之间是隔离的不会导致环境之间的污染 2.虚拟环境管理模块的安装  1.windows系统:pipinstallvirtualenvwra... 查看详情

构建环境隔离和文件系统差异

】构建环境隔离和文件系统差异【英文标题】:Buildenvironmentisolationandfilesystemdiffing【发布时间】:2014-01-2823:21:12【问题描述】:好吧,所以在第n次尝试追踪各种软件的依赖关系并复制各种人为所有不同的linux发行版所做的工作之... 查看详情

火山引擎dataleap一招教你避坑“数据开发”中的资源隔离问题

...义等,且支持任务级别引用,快速帮助研发团队实现资源隔离。火山引擎DataLeap“项目参数管理”能力以湖仓一体分析服务(LAS)引擎为例,介绍如何利用“项目参数管理”区分不同环境库和时间格式的查询。在使用之前,由于1... 查看详情

了解docker

...,需要调试很久。常规方法可以创建不同的虚拟机将环境隔离,但是虚拟机开销大。docker可以实现虚拟机的隔离应用环境功能,同时开销比它小( 查看详情

dubbo3终极特性「流量治理体系」一文教你如何通过dubbo-admin实现动态进行流量隔离机制(代码片段)

...0c;则可以使用标签路由对不同环境中的不同版本进行流量隔离,将秒杀订单流量或不同渠道订单流量路由到特殊环境,将正常的流量路由到日常环境。即使特殊环境异常,本应进入特殊环境的流量也不会进入日常环境... 查看详情

记一个mysql环境rr隔离级别转换成rc的问题

先了解RR(REPEATABLE-READ)和RC(READ-COMMITTED)的区别.RR隔离级别增加了间隙锁,避免了幻读,并且阻止了不可重复读,让同一个事务里面的查询和修改都是一致的.mysql默认的隔离级别就是RR.虽然说RC隔离级别在同一个事务内会存在查询出不同... 查看详情

flask框架搭建虚拟环境教程(linux)(代码片段)

...境可以为每一个项目安装独立的Python库,这样就可以隔离不同项目之间的Python库,也可以隔离项目与操作系统之间的Python库。管理虚拟环境的常用的工具 查看详情

docker实践入门之一

...一种容器技术,它的主要功能就是能够让进程在一个隔离的容器环境里运行——在进程看来,它有一整套“独立”的OS环境,包括文件系统,类似于虚拟机。docker不是什么?docker不是虚拟机,它只是一套虚... 查看详情