springboot学习19

本文详细介绍了如何在Spring Boot应用中集成ActiveMQ和Artemis,包括设置JMS依赖、配置Broker连接、使用JmsTemplate发送和接收消息,以及消息转换和后期处理。同时,展示了如何通过@JmsListener实现消息监听器的被动消费。
摘要由CSDN通过智能技术生成

一、异步信息-使用JMS
1、设置 JMS
pom.xml引入依赖:
如果使用ActiveMQ:

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

ActiveMQ 特定的属性:

属性描述
spring.activemq.broker-urlBroker 的 URL
spring.activemq.user用于访问 Broker 的用户(可选)
spring.activemq.password用于访问 Broker 的密码(可选)
spring.activemq.in-memory是否启动内存 Broker(默认:true)

application.yml:

spring:
  activemq:
	# 使用单个属性 spring.activemq.broker-url 指定 ActiveMQ Broker 的地址
    broker-url: tcp://testdemo.springbootlearn.com  
    user: learndemouser
    password: 123456

如果使用 ActiveMQ Artemis:
Artemis 是 ActiveMQ 的下一代重新实现。

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

Artemis 属性:

属性描述
spring.artemis.hostbroker 主机
spring.artemis.portbroker 端口
spring.artemis.user用于访问 broker 的用户(可选)
spring.artemis.password用于访问 broker 的密码(可选)

application.yml:

spring:
  artemis:
	# 创建到监听 testdemo.springbootlearn.com(端口 61617)的 Artemis Broker 的 broker 连接
    host: testdemo.springbootlearn.com	
    port: 61617
    user: learndemouser
    password: 123456

如果使用 ActiveMQ,则需要设置 spring.activemq.in-memory 属性为 false,以防止 Spring 启动内存中的 Broker。

2、使用 JmsTemplate 发送消息
JmsTemplate主要方法:

// 发送原始消息,需要一个 MessageCreator 来制造一个 Message 对象
void send(MessageCreator messageCreator) throws JmsException;
void send(Destination destination, MessageCreator messageCreator) throws JmsException;
void send(String destinationName, MessageCreator messageCreator) throws JmsException;
// 发送转换自对象的消息,接受一个 Object,并在后台自动将该 Object 转换为一条 Message
void convertAndSend(Object message) throws JmsException;
void convertAndSend(Destination destination, Object message) throws JmsException;
void convertAndSend(String destinationName, Object message) throws JmsException;
// 发送经过处理后从对象转换而来的消息,会自动将一个 Object 转换成一条 Message,
// 但也会接受一个 MessagePostProcessor,以便在 Message 发送前对其进行定制
void convertAndSend(Object message, MessagePostProcessor postProcessor) throws JmsException;
void convertAndSend(Destination destination, Object message, MessagePostProcessor postProcessor) throws JmsException;
void convertAndSend(String destinationName, Object message, MessagePostProcessor postProcessor) throws JmsException;

三个方法类别中的每一个都由三个重载的方法组成,它们是通过指定 JMS 目的地(队列或主题)的方式来区分的。

一个方法不接受目的地参数,并将消息发送到默认目的地。
一个方法接受指定消息目的地的目标对象。
一个方法接受一个 String,该 String 通过名称指定消息的目的地。

JmsOrderMessagingService

package xxx.springlearndemo.service.messaging;import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;@Service
public class JmsOrderMessagingService{
    
    private JmsTemplate jms;
    
    @Autowired
    public JmsOrderMessagingService(JmsTemplate jms) {
        this.jms = jms;
    }
       

//   方法1:
//    @Override
//    public void sendOrder(Order order) {
//        jms.send(new MessageCreator() {
//            @Override
//            public Message createMessage(Session session)
//                throws JMSException {
//                return session.createObjectMessage(order);
//            }
//        });
//    }

	// 方法2:
	// lambda 表达式
	@Override
	public void sendOrder(Order order) {
		jms.send(session -> session.createObjectMessage(order));
	}


}

上面代码方法1,方法2中的 jms.send() 的调用没有指定目的地,
还必须使用 spring.jms.template.default-destination 属性指定一个默认的目的地名称。
可以在 application.yml 中设置属性:

spring:
  jms:
    template:
      default-destination: springlearndemo.order.queue

如果需要将消息发送到缺省目的地之外的目的地,则需要将该目的地指定为 send() 方法的参数。
声明一个 Destination bean,然后将其注入执行消息传递的 bean。

package xxx.springlearndemo.service.messaging;
// Artemis的ActiveMQQueue类。
// 还有一个是 ActiveMQ的ActiveMQQueue类。org.apache.activemq.command。
import  org.apache.activemq.artemis.jms.client; 	

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;@Service
public class JmsOrderMessagingService { 
  
    private JmsTemplate jms;    
    
    private Destination orderQueue;

//  Destination bean 被注入到 JmsOrderMessagingService,
//  可以在调用 send() 时使用它来指定目的地
    @Autowired
    public JmsOrderMessagingService(JmsTemplate jms, Destination orderQueue) {
        this.jms = jms;
        this.orderQueue = orderQueue;
    }
	// ...

	public Destination orderQueue() {
	    return new ActiveMQQueue("springlearndemo.order.queue");
	}

	@Override
	public void sendOrder(Order order) {
	   jms.send(
	       orderQueue,
	       session -> session.createObjectMessage(order));
	}
	// 指定了目的地名称,将名称作为 send() 的第一个参数
	@Override
	public void sendOrder(Order order) {
	   jms.send(
	       "springlearndemo.order.com",
	       session -> session.createObjectMessage(order));
	}	
}

1)在发送前转换消息:
使用JmsTemplates的convertAndSend() 方法,不需要提供 MessageCreator。

package xxx.springlearndemo.service.messaging;

import javax.jms.JMSException;
import javax.jms.Message;

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

import xxx.springlearndemo.Order;

@Service
public class JmsOrderMessagingService implements OrderMessagingService {

  private JmsTemplate jms;

  @Autowired
  public JmsOrderMessagingService(JmsTemplate jms) {
    this.jms = jms;
  }
  
  // convertAndSend() 将接受 Destination 或 String 值来指定目的地,
  // 或者可以完全忽略目的地来将消息发送到默认目的地。
  @Override
  public void sendOrder(Order order) {
    jms.convertAndSend("springlearndemo.order.queue", order,
        this::addOrderSource);
  }
  
  // 自定义头信息
  private Message addOrderSource(Message message) throws JMSException {
    message.setStringProperty("X_ORDER_SOURCE", "WEB");
    return message;
  }

}

2)配置消息转换器
MessageConverter接口提供了2个方法。

public interface MessageConverter {
    Message toMessage(Object object, Session session)
        throws JMSException, MessageConversionException;
    
    Object fromMessage(Message message);
}

spring 已经提供了一些MessageConverter的实现如下:
其中SimpleMessageConverter 是默认的消息转换器。使用它的前提是发送的对象实现 Serializable 接口。

消息转换器描述
MappingJackson2MessageConverter使用 Jackson 2 JSON 库对消息进行与 JSON 的转换
MarshallingMessageConverter使用 JAXB 对消息进行与 XML 的转换
MessagingMessageConverter使用底层 MessageConverter(用于有效负载)和JmsHeaderMapper(用于将 Jms 信息头映射到标准消息标头)将 Message 从消息传递抽象转换为 Message,并从 Message 转换为 Message
SimpleMessageConverter将 String 转换为 TextMessage,将字节数组转换为 BytesMessage,将 Map 转换为 MapMessage,将Serializable 转换为 ObjectMessage

3)后期处理消息
使用 MessagePostProcessor 在消息发送之前添加 X_ORDER_SOURCE 头信息

jms.convertAndSend("springlearndemo.order.queue", order,
    new MessagePostProcessor() {
        @Override
        public Message postProcessMessage(Message message)
            throws JMSException {
            message.setStringProperty("X_ORDER_SOURCE", "WEB");
            return message;
        }
});

lambda :

jms.convertAndSend("springlearndemo.order.queue", order,
    message -> {
        message.setStringProperty("X_ORDER_SOURCE", "WEB");
        return message;
    });

3、接收 JMS 消息
消费消息: 拉模型 推模型
JmsTemplate 几种接收消息都使用拉模型
1)使用 JmsTemplate 接收
JmsTemplate 的拉模型,拉模式的方法:

// 方法接收原始消息
Message receive() throws JmsException;
Message receive(Destination destination) throws JmsException;
Message receive(String destinationName) throws JmsException;

// 使用配置的消息转换器将消息转换为域类型
// 其中的每一个,可以指定 Destination 或包含目的地名称的 String,
// 也可以从缺省目的地获取一条消息
Object receiveAndConvert() throws JmsException;
Object receiveAndConvert(Destination destination) throws JmsException;
Object receiveAndConvert(String destinationName) throws JmsException;

使用receive():
JmsOrderReceiver

package xxx.springbootlearn.messaging.jms;

import javax.jms.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;

@Component
public class JmsOrderReceiver {
    
    private JmsTemplate jms;
    private MessageConverter converter;
    
    @Autowired
    public JmsOrderReceiver(JmsTemplate jms, MessageConverter converter) {
        this.jms = jms;
        this.converter = converter;
    }
    
    // 使用 receive()
    public Order receiveOrder() {
        // 使用了一个 String 来指定从何处拉取订单
        Message message = jms.receive("springlearndemo.order.queue");
        // Object 返回的,在返回它之前需要进行转换
        return (Order) converter.fromMessage(message);
    }
}

使用 receiveAndConvert():
这样就不需要注入 MessageConverter,因为所有的消息转换都将在 receiveAndConvert() 中完成。

package xxx.springbootlearn.messaging.jms;

import javax.jms.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;

@Component
public class JmsOrderReceiver {
    
    private JmsTemplate jms;
    
    @Autowired
    public JmsOrderReceiver(JmsTemplate jms) {
        this.jms = jms;
    }
    
   	// 使用 receiveAndConvert() 
    public Order receiveOrder() {
        return (Order) jms.receiveAndConvert("springlearndemo.order.queue");
    }
    
}

2)声明消息监听器
与拉模型不同,消息监听器是一个被动组件,在消息到达之前是空闲的。
@JmsListener 注解

package xxx.springbootlearn.messaging.jms.listener;

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

@Component
public class OrderListener {
	//...

    // 被动地监听消息
    // Spring 中的框架代码将等待消息到达指定的目的地,
    // 当消息到达时,receiveOrder() 方法将自动调用,并将消息的 Order 作为参数
    @JmsListener(destination = "springlearndemo.order.queue")
    public void receiveOrder(Order order) {
        // ...
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值