Spring集成Artemis实现JSM的异步消息传递


JMS是一套Java定义的标准,用于在程序之间进行消息的流通。

一、概念逻辑

JMS的逻辑如下:

发布信息的称为JMS生产者,生产者将信息发送给JMS服务器,同时说明发送到的目的地(Destination),JMS服务器将消息保存在对应目的地的一个队列(queue)中,等待JMS消费者领取。

JMS消费者有两种领取信息的方式,一种是拉(pull)模式,即发出收取消息的请求,等待直到队列中有消息到达为止;一种是推(push)模式,即由容器监听目标队列,消息到达时通知对应的消费者进行处理。

这样的模式意味着信息的传送可以不一定是一对一的。对发送到队列的信息,消费者提取后即pop掉。

JMS服务器(MQ,消息队列,在Artemis里称broker)常用apeche的ActiveMQ,以及其新版本Artemis。在本地或远程部署Artemis实例后即可使用。

Spring提供了一套JMS实现,即JMSTemplate,可用它写出消费者和生产者,与Artemis交互。

二、引入依赖及配置

要在Spring项目中使用artemis,可在maven用springboot starter引入相应的框架:

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

在application.yml中,可以对Artemis做一些配置。如果只是使用本地的Artemis broker实例,可以不做任何配置。

配置示例如下:

spring:
  artemis:
    broker-url: tcp://api.mcyou.cc
    user: admin
    password: passwd

这里配置了broker的地址、用户名及密码。注意它是基于tcp的。

接下来要下载并创建artemis实例。首先在Apeche网站下载artemis,然后进入其lib,使用命令artemis create 目标目录 来在目标位置创建一个实例。创建时会要求输入想要的用户名及密码。

完成后来到实例的目录,进入/bin/,执行artemis run即可运行该实例。

三、创建生产者

import org.apache.activemq.artemis.jms.client.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;

import javax.jms.Destination;

@Service
public class JmsMessagingService {
    private JmsTemplate jms;
    private Destination messageQueue = new ActiveMQQueue("cc.mcyou.queue");;

    @Autowired
    public JmsMessagingService(JmsTemplate jms){
        this.jms = jms;
    }

    public void sendUser(User user){
        jms.send(messageQueue, session -> session.createObjectMessage(user));
    }

    public void sendUser2(User user){
        jms.convertAndSend("cc.mcyou.queue", user);
    }
}

导入一个JmsTemplate,然后使用jms实例即可完成发送操作。

这里sendUser方法和sendUser2方法展示了两种发送对象的方式。sendUser方法使用jms.send方法,需要使用MessageCreator来构造Message;sendUser2方法直接使用convertAndSend方法,发送对象更方便一些。

对于每个发送,都要指定一个Destination。这里既可以构造一个Destination对象,也可以直接用字符串表明destination的名字,传递给artemis处理。

四、创建拉模式的消费者

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class JmsMessageReceiver {

    private JmsTemplate jms;

    @Autowired
    public JmsMessageReceiver(JmsTemplate jms){
        this.jms = jms;
    }

    public User receiveUser(){
        return (User)jms.receiveAndConvert("cc.mcyou.queue");
    }
}

还是通过Spring容器注入一个JmsTemplate的实例。在接收信息时,对应发送信息时的方法名,这里同样可以用receive方法或receiveAndConvert方法,且同样要指定一个接收的目的地。接收对象时直接用receiveAndConvert比较简单。如果用receive方法,需要手动注入一个MessageConverter对其进行转换。

注意对于拉模式的这种receive等方法,在调用时进程会被阻塞,等待信息到达。

五、创建推模式的消费者

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class UserListener {

    @JmsListener(destination = "cc.mcyou.queue")
    public void receiveUser(User user){
        System.out.println("收到用户:"+user.name);
    }
}

推模式是一个Listener的模式。使用注解@JmsListener注册监听器,同时指定destination。这样这个方法就交给Spring挂起,等待消息到达时由Spring调用这个方法,进行后续的处理。

推模式的最大好处在于不会阻塞进程,比较适合需要保证可用性的场景。

使用Spring提供的模板实现JMS,然后与Artemis通信,这样就使得限定于Java的JMS得以利用跨语言的Artemis进行通信。当然基于JMS的信息仍然必须由基于JMS的消费者接受才能利用。

最后更新于