Spring Boot整合ActiveMQ及场景举例(点对点模式、订阅模式)

目录

 

前序

为什么要引入MQ

注册案例——不使用MQ

注册案例——引入MQ(点对点模式)

注册案例——引入MQ(发布/订阅模式)

安装Active MQ

使用Spring Boot进行整合(点对点模式)

引入依赖包

 在application.properties做出配置

创建消费者

创建消费者

运行调试

使用Spring Boot进行整合(发布/订阅模式)

修改application.properties配置文件

修改生产者

修改消费者

运行结果

小结


前序

技术圈对Spring Boot的应用越来越广泛了,它有着强大的生态环境,各种主流的组件都被它纳入其中,WebSocket、各种MQ、Redis、Solr、mongoDB等等。它的老爹是Spring开发团队,在前后端分离、分布式、微服务的今天,用Spring Boot开发后端API接口简直是行云流水。

整合一个中间件,传统的Java Web项目或者SSM、SSH架构下的项目可能需要好多篇代码,而且我们要自己去管理连接、维护连接池,在Spring Boot当中只需要做一些简单的配置,简单到怀疑会因为东西太少而报错……

今天我们就整合Active MQ,在开始之前,先聊一下为什么要使用MQ。

为什么要引入MQ

市场上有很多成熟的MQ中间件,Rabbit MQ、Kafka、Active MQ等等,这里介绍的MQ不针对某一个产品,而是针对这一类产品。

网上有很多文章都说MQ的优点,削峰、解耦、异步,但大多是一笔带过,究竟怎样解耦、异步、削峰呢?本文将以一个实际的场景为大家介绍。

来看一个很形象的例子吧,假如在你的系统中,如果有用户注册了账号,你就要往此用户的手机、邮箱各发送一条信息,看一下没有引入MQ的实现方式:

注册案例——不使用MQ

 以上的实现方式,有什么弊端呢?

第一,代码耦合度高、侵入性强,我们将发送手机信息、邮箱信息的代码写入到了业务方法中,使我们的业务代码看起来比较臃肿,不优雅;而且如果有第三方接口的服务不可用了,那你总不能让程序停掉吧,总要去处理异常,所以try-catch块更是让我们的业务代码变得复杂。实际上处理用户注册的请求,业务方法应该只有将信息入库,其他的操作都不应该出现。

第二,可扩展性、可维护性、可读性差,为什么这么说?假如后来的业务规则有变化,需要用手机号调用一下另一个接口,那此时你就需要在原来的业务代码里继续写,哪怕你封装成最优秀、最简洁的工具类,你不还是得在业务方法中调用吗?如此往复,如果业务不断增加、改变,你觉得你能坚持多久?简单的一段注册业务,被改的面目全非,注释满天飞,可读性也不强。

第三,影响主线程的处理,用户体验差。用户提交了注册请求,还得等到你所有的第三方接口调用成功之后才能得到响应,用户根本不关心这些,哪怕你的信息没有发送成功,只要他可以登录系统就好。我们经常在一些网站或者APP注册账号之后,过一段时间才会收到手机信息,但当你提交注册信息之后已经立马进入到系统中了,这也是类似于MQ的实现方式。另外一点,如果其中的某一个接口响应过慢呢?主线程就会阻塞住,因为代码是从上往下执行的嘛。再往下推理,如果有多个请求进来,就会有多个Tomcat线程被挂起,你觉得你的服务器能承受多久?

看到了吧,这就是古老的方式,这种架构下,你敢说你的系统能承受高并发吗?

注册案例——引入MQ(点对点模式)

假如我们的需求依然只是发送手机短信、邮箱信息,我们采用点对点的方式:

点对点的方式,就是一对一的关系,消息写到一个队列(queue)中,只有一个消费者可以收到。

以上我们通过点对点的方式,将用户的手机号、邮箱写入到了消息队列中,供消费者消费信息,执行其他的业务。

主线程接收到请求之后,只需要把用户的手机号、邮箱写入到消息队列中,告诉消费者我要往这个手机号、邮箱发送信息,这个任务就交给你了,我直接返回给用户响应信息。

这样一来,首先达到了解耦,我们的主线程只是做一下通知,下达一个任务就不再关心怎么实现了,由消费者去执行其他业务,甚至信息入库这个操作,你也可以通过阻塞队列来实现,将数据库操作放到阻塞队列中,由多个线程去监听这个阻塞队列;

其次加快了响应时间,主线程只是往消息队列中写入一条消息,并没有真正的执行业务,而且现在的MQ中间件特别成熟,写入消息的时间完全可以忽略不计。

注册案例——引入MQ(发布/订阅模式)

假如现在我们的需求有变更,仍然用刚才的例子,需要用手机号调用其他的业务接口,那么我们怎样扩展呢?

这时候就需要用到发布订阅模式了,发布/订阅模式和点对点的区别?

这种模式下,生产者将消息写入到一个主题(topic),注意跟上面的queue不一样,点对点模式下是queue—consumer,即队列—消费者的模式,而此时是topic—subscriber,即主题—订阅模式。消息写入到topic之后,只要订阅了这个主题的订阅者都可以收到消息。看一下流程图:

 以上,我们采用发布/订阅模式,将信息写入到对应的topic,可以有多个订阅者去消费消息,执行不同的业务,但对于主线程来说,仍然只是往MQ中写入一条消息,是不是很强大?

这样一来,系统的可扩展性大大提高,假如后来对手机号、邮箱又有新的需求,那么我们只需要编写对应的订阅者业务逻辑,去订阅对应的topic即可,主线程的代码完全不需要修改,就可以实现复杂、多元的第三方业务。

安装Active MQ

本文以Active MQ为例。此MQ的安装,特别简单,下载下来之后解压出来,进入bin目录运行activemq.bat即可,可参考这个:

https://jingyan.baidu.com/article/b0b63dbf33232d4a4930705f.html

使用Spring Boot进行整合(点对点模式)

创建Spring Boot项目就不说了,可参考我之前的文章,或者网上一搜一大堆。

注意:这里有一个大坑,Spring Boot的版本最好是2.0.x,不要是2.1.x,因为博主亲测发现,2.1.x版本的Spring Boot在整合Active MQ时不能开启连接池,否则就报错,注入不了依赖。

引入依赖包

除了Spring Boot项目的基础依赖以外,在pom.xml添加如下两个依赖包:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <!--消息队列连接池-->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
            <version>5.15.0</version>
        </dependency>

在启动类上加@EnableJms注解

在启动类上加上此注解,开启JMS消息服务,否则会报错。

package com.dosion.wang.demo;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.jms.annotation.EnableJms;
/**
 *  开启消息队列
 * */
@EnableJms
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

 在application.properties做出配置

# ActiveMQ相关配置
spring.activemq.broker-url=tcp://localhost:61616
# 不使用Spring Boot内部的ActiveMQ,连接我们自己的MQ服务器
spring.activemq.in-memory=false
# 使用连接池
spring.activemq.pool.enabled=true
# 连接池最大连接数
spring.activemq.pool.max-connections=100
# 空闲连接的过期时间,30秒
spring.activemq.pool.idle-timeout=30000
# 是否采取订阅模式,false,先采取点对点模式
spring.jms.pub-sub-domain=false

创建消费者

这里直接写到Controller层中:

package com.dosion.wang.demo.controller;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


/**
 *  ActiveMQ控制器,Demo自测
 * @author 秋枫艳梦
 * @date 2019-07-19
 * */
@RestController
@RequestMapping(value = "/message" , produces = {"application/json;charset=utf-8"})
public class ActiveMQController {

    //注入Spring Boot自带的工具类
    @Autowired
    private JmsMessagingTemplate messagingTemplate;

    /**
     *  向ActiveMQ推送消息
     * @param message 前台传来的消息
     * @return 操作码
     * */
    @RequestMapping(value = "/push")
    public Object pushMessage(@RequestParam("message") String message){
        //点对点模式,将消息写入register-queue队列,若队列不存在会自动创建
        messagingTemplate.convertAndSend("register-queue",message);
        //需要引入fastjson依赖
        return JSON.parseObject("{\"message\":\"push a message success\",\"messageCode\":200}");
    }

    /**
     *  此方法用于接收消费者、订阅者的反馈,比如返回是否执行成功,再决定其他的提交、回滚、重试操作
     * @param message 消费者、订阅者返回的消息,此处定义将返回信息写入到return-register队列
     * */
    @JmsListener(destination = "return-register")
    public void returnMsgOne(String message){
        System.out.println("订阅者说:"+message);
    }
}

创建消费者

以下代码中的注解,会使项目一启动就开始监听,特别方便:

package com.dosion.wang.demo.listener;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;

/**
 *  消息队列监听
 * @author 秋枫艳梦
 * @date 2019-07-19
 * */
@Component
public class ActiveMQListener {

    /**
     * 将反馈信息写入到return-register队列,供生产者回调
     * @param message 接收到的消息,此参数会自动注入
     * @return 返回给生产者的信息
     * */
    @JmsListener(destination = "register-queue")
    @SendTo("return-register")
    public Object listenQueue(String message){
        System.out.println("获取到消息:"+message);
        return "我是此队列的消费者,已收到消息,执行业务......";
    }
}

运行调试

在浏览器访问我们的API:

后台打印内容:

 这就是Spring Boot,引入依赖,两篇简短的代码,几个注解,就可以实现消息队列的使用以及回调。试想一下,如果自己去实现工具类、管理连接、配置实例,需要多少的代码量呢?

使用Spring Boot进行整合(发布/订阅模式)

只需要修改少量的代码即可:

修改application.properties配置文件

修改以下一行代码,采用topic模式:

spring.jms.pub-sub-domain=true

修改生产者

package com.dosion.wang.demo.controller;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


/**
 *  ActiveMQ控制器,Demo自测
 * @author 秋枫艳梦
 * @date 2019-07-19
 * */
@RestController
@RequestMapping(value = "/message" , produces = {"application/json;charset=utf-8"})
public class ActiveMQController {

    //注入Spring Boot自带的工具类
    @Autowired
    private JmsMessagingTemplate messagingTemplate;

    /**
     *  向ActiveMQ推送消息
     * @param message 前台传来的消息
     * @return 操作码
     * */
    @RequestMapping(value = "/push")
    public Object pushMessage(@RequestParam("message") String message){
        //发布、订阅模式,将消息写入register-topic主题。其实调用的方法一样,只是注释换了一下、主题名称改了一下
        //Spring boot会根据配置文件中是否采用topic模式,选择是创建队列还是创建主题
        messagingTemplate.convertAndSend("register-topic",message);
        //需要引入fastjson依赖
        return JSON.parseObject("{\"message\":\"push a message success\",\"messageCode\":200}");
    }

    /**
     *  此方法用于接收消费者、订阅者的反馈,比如返回是否执行成功,再决定其他的提交、回滚、重试操作
     * @param message 消费者、订阅者返回的消息,此处定义将返回信息写入到return-register队列
     * */
    @JmsListener(destination = "return-register")
    public void returnMsgOne(String message){
        System.out.println("订阅者说:"+message);
    }
}

修改消费者

package com.dosion.wang.demo.listener;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;

/**
 *  消息队列监听
 * @author 秋枫艳梦
 * @date 2019-07-19
 * */
@Component
public class ActiveMQListener {

    /**
     * 第一个订阅者
     * @param message 接收到的消息,此参数会自动注入
     * @return 返回给生产者的信息
     * */
    @JmsListener(destination = "register-topic")
    @SendTo("return-register")
    public Object listenQueue(String message){
        System.out.println("第一个订阅者获取到消息:"+message);
        return "我是第一个订阅者,已成功执行,请将消息删除或提交";
    }

    /**
     *  第二个订阅者
     *
     * */
    @JmsListener(destination = "register-topic")
    @SendTo("return-register")
    public Object listenTwo(String message){
        System.out.println("第二个订阅者获取到消息:"+message);
        return "我是第二个订阅者,我执行失败了,请进行重试";
    }
}

运行结果

小结

以上就是Spring Boot整合Active MQ的全部内容,你是否掌握了MQ的应用场景呢?

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值