【本文内容】
- MQ介绍
- 介绍
IBM MQ
messaging模型 - 通过
docker
安装IBM MQ
IBM MQ Console
介绍- 【Java代码示例】使用
JMS
与IBM MQ
集成(Spring Boot
)
1. Message Queue vs Restful APIs
参考:www.youtube.com/watch?v=ynj…
消息队列(Message Queue)是为了解决数据的发送问题,从一端到送到另一端。
那么为什么不用Restful APIs? 技术上当然也可以这么实现:
- 一般情况下用Restful APIs调用是同步的,如果app1产生的数据过快,作为消费端的app2无法应对,那么会造成app2系统的奔溃。
- 并且相互侵入的代码较多,如果有很多app相互调用的话,就会变的相对复杂。
- 或许还要解决app之间调用的security问题。
如果使用MQ来实现:
- 那么消息的发送是异步的,如果app1产生的数据过快,作为消费端的app2也可以按照自己的速度消费。
- app之间可以解耦,发送方只需要负责将数据发送到Broker中,消费方只需要监听Broker的消息。app1和2之间并不需要直接产生连接。
IBM MQ提供了以下功能:
- Communication
- Security
- Transactions
- Persistence
- Scale
- Recovery
2. 介绍IBM MQ messaging模型
参考:www.youtube.com/watch?v=U03…
- putting and getting messages
- point-to-point messaging
- publish-subscribe (event-driven messaging)
- request-response messaging
- message expiry
2.1 putting and getting messages
在IBM MQ中,发送消息,通常跟Queues
, Topics
有关。
2.2 端到端的消息发送
适用的场景如,我们想要往数据库存放数据,如果同一时间有海量的数据存入,可能会导致数据库崩溃,这时候我们可以先把数据放到IBM MQ的Queue
中,然后数据库一条一条的消费,再存入。
2.3 publish-subscribe (event-driven messaging)
订阅模式,即生产者往IBM MQ的Topic
中发送消费,那么所有订阅了该Topic的消费端(可能很多个)都能收到消息。
2.4 request-response messaging
生产者在发送消息的时候,渴望消费端在消费完消息后再通知生产者。 这时候会有一个临时的queue,消费端在消费完后往这个临时的queue中发送回执。
比如一个售票的app,在接到客户的买票请求后,从航空公司下订单并支付,这时候航空公司可以将票作为回执。进来app再将票返回给客户。【这个场景有点像同步的Restful API调用】
2.5 message expiry
消息是有时间限制的,在Queue中未被消费的过期消息,将无法再被消费。
3. 通过docker安装IBM MQ
参考:www.youtube.com/watch?v=xBX…
Docker hub:hub.docker.com/r/ibmcom/mq
3.1 拉取最新版本的镜像
docker pull ibmcom/mq:latest
下载好后,可以通过docker images
查看镜像:
3.2 创建docker volume
创建volume是为了将数据持久化到本地磁盘,以便ibm mq在重启后数据不丢失。
为啥叫qm1data
,是因为我们要创建的queue manager就叫qm1
。
docker volume create qm1data
3.3 启动容器
docker run --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --volume qm1data:/mnt/mqm --publish 1414:1414 --publish 9443:9443 --detach --env MQ_APP_PASSWORD=passw0rd ibmcom/mq:latest
LICENSE=accept
表示在容器内我们accept mq的licenseMQ_QMGR_NAME=QM1
表示我们创建了一个MQ Server/或叫queue manager,名称为QM1volume
:我们把容器内的目录/mnt/mqm目录印射到volume=qm1data上1414
端口为应用程序通过该端口连接到ibm mq上,因为app可能在本地,所以用-p暴露出来,以便可以在本地连到docker的ibm mq中。9443
端口为ibm mq consoledetach
表示在后台运行MQ_APP_PASSWORD
表示app连接到mq的时候需要通过这个密码
可以通过docker ps
查看:
3.4 进入容器内部以进行测试
以bath shell的方式进入容器内进行交互:
docker exec -it 22581b03a450 bash
开始测试:
3.4.1 显示版本:display my mq version
dspmqver
可以看到版本为9.2.4.0,运行的License类型为Developer:
3.4.2 查看mq server/mq manager:display mq
dspmq
可以看到我们有一个queue manager,即上述创建的名字叫:MQ1。
4. Console
参考:
我们在#3中通过docker启动ibm mq的时候,同时也对外暴露了console的端口:9443,所以可以直接访问:https://localhost:9443/ibmmq/console/login.html
默认的用户名密码:
- User: admin
- Password: passw0rd
在本地队列管理器中可以看到我们创建的QM1
:
IBM MQ会默认创建以下Queue,当然我们也可以点击【创建】按纽自行创建:
5. Java代码示例:使用JMS与IBM MQ集成
参考:developer.ibm.com/tutorials/m…
JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。(参考:JMS解析(一)——JMS简介)
5.1 加上MQ Spring Starter
a. 首先是依赖:
spring-boot-starter-web
是Spring Boot的依赖。mq-jms-spring-boot-starter
是Spring Boot与mq-jms的集成,IBM MQ的操作等需要这个jar。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>mq-jms-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
b. 在resource下加上IBM MQ的配置
在application.properties
中加上以下内容:
ibm.mq.queueManager=QM1
ibm.mq.channel=DEV.ADMIN.SVRCONN
ibm.mq.connName=localhost(1414)
ibm.mq.user=admin
ibm.mq.password=passw0rd
c. Spring Boot的入口类:
除了@SpringBootApplication
这个主要的注解外,还需要加上@EnableJms
注解,这个注解会帮忙发现注解@JmsListener
。
@SpringBootApplication
@EnableJms
public class IBMMQApplication {
public static void main(String[] args) {
SpringApplication.run(IBMMQApplication.class, args);
}
}
5.2 通过JmsTemplate
向IBM MQ发送消息
IBM MQ Spring Boot Starter
会基于上述的application.properties
创建JmsTemplate
,可以通过@Autowired引入。
我们往默认的队列"DEV.QUEUE.1"
中发送消息:
@RestController
public class MessageController {
@Autowired
private JmsTemplate jmsTemplate;
@GetMapping("send")
public boolean convertAndSend() {
jmsTemplate.convertAndSend("DEV.QUEUE.1", "Test message, hello ibm mq!");
return true;
}
}
5.3 通过@JmsListener
接收消息
@JmsListener会默认为我们创建一个JmsListenerContainerFactory
,如果想要自定义传入,可通过参数containerFactory
传入:
@Component
public class JMSMessageReceiver {
@JmsListener(destination = "DEV.QUEUE.1")
public void receiveMessage(String data) throws Exception {
System.out.println("Received <" + data + ">");
}
}
【测试】
在页面上调用:http://localhost:8080/send
后台会接收到消息并打印:Received <Test message, hello ibm mq!>