概述

Spring 提供了一个简化 JMS API 使用的集成框架。

本教程将介绍此类集成的基本概念。

2. Maven 依赖

为了在应用中使用 Spring JMS,我们需要在 pom.xml 中添加必要的依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
    <version>4.3.3.RELEASE</version>
</dependency>

您可以在此处找到最新版本的依赖项:https://mvnrepository.com/artifact/org.springframework/spring-jms

3. JmsTemplate

JmsTemplate 类负责在发送或同步接收消息时创建和释放资源。

因此,使用此 JmsTemplate 的类只需要实现方法定义中指定的回调接口即可。

从 Spring 4.1 开始,JmsMessagingTemplate 基于 JmsTemplate 构建,提供了与消息抽象(org.springframework.messaging.Message)的集成,从而允许我们以通用方式创建发送的消息。

4. 连接管理

为了连接并能够发送/接收消息,我们需要配置一个 ConnectionFactory

ConnectionFactory 是由管理员预先配置的 JMS 管理对象之一。客户端通过配置与 JMS 提供商建立连接。

Spring 提供了两种类型的 ConnectionFactory

  • SingleConnectionFactory - 实现 ConnectionFactory 接口,所有 createConnection() 调用返回相同的连接,并忽略 close() 调用
  • CachingConnectionFactory - 扩展了 SingleConnectionFactory 功能,并增强了对会话、MessageProducerMessageConsumer 的缓存

5. 目的地管理

如上所述,除了 ConnectionFactory 之外,目的地也是 JMS 管理的对象,可以从 JNDI 存储和检索。

Spring 提供了通用解析器(如 DynamicDestinationResolver)和特定解析器(如 JndiDestinationResolver)。

JmsTemplate 将根据我们的选择将目的地名称的解析委托给其中一个实现。

它还提供了一个名为 defaultDestination 的属性,将在不引用特定目的地的 sendreceive 操作中使用。

6. 消息转换

没有消息转换支持,Spring JMS 就不完整了。

JmsTemplate 对于 convertAndSend()receiveAndConvert() 操作的默认转换策略是 SimpleMessageConverter 类。

SimpleMessageConverter 能处理 TextMessagesBytesMessagesMapMessagesObjectMessages。这个类实现了 MessageConverter 接口。

SimpleMessageConverter 之外,Spring JMS 还提供了一些内置的 MessageConverter 类,如 MappingJackson2MessageConverterMarshallingMessageConverterMessagingMessageConverter

此外,只需实现 MessageConverter 接口的 toMessage()fromMessage() 方法,即可创建自定义消息转换功能。

下面是一个实现自定义 MessageConverter 的示例代码片段:

public class SampleMessageConverter implements MessageConverter {
    public Object fromMessage(Message message) 
      throws JMSException, MessageConversionException {
        //...
    }

    public Message toMessage(Object object, Session session)
      throws JMSException, MessageConversionException { 
        //...
    }
}

7. 示例 Spring JMS

在本节中,我们将了解如何使用 JmsTemplate 发送和接收消息。

默认的发送消息方法是 JmsTemplate.send()。它有两个关键参数:第一个是 JMS 目的地,第二个是实现 MessageCreator 的实例。JmsTemplate 使用 MessageCreator 的回调方法 createMessage() 来构建消息。

JmsTemplate.send() 适合发送纯文本消息,但要发送自定义消息,可以使用 JmsTemplate.convertAndSend() 方法。

下面是这些方法的实现:

public class SampleJmsMessageSender {

    private JmsTemplate jmsTemplate;
    private Queue queue;

    // setters for jmsTemplate & queue

    public void simpleSend() {
        jmsTemplate.send(queue, s -> s.createTextMessage("hello queue world"));
    }
    public void sendMessage(Employee employee) { 
        System.out.println("Jms Message Sender : " + employee); 
        Map<String, Object> map = new HashMap<>(); 
        map.put("name", employee.getName()); map.put("age", employee.getAge()); 
        jmsTemplate.convertAndSend(map); 
    }
}

以下是消息接收类,即消息驱动的 POJO(MDP)。可以看到,SampleListener 类实现了 MessageListener 接口,并提供了接口方法 onMessage() 的文本特定实现。

除了 onMessage() 方法,SampleListener 类还会调用 receiveAndConvert() 方法来接收自定义消息:

public class SampleListener implements MessageListener {

    public JmsTemplate getJmsTemplate() {
        return getJmsTemplate();
    }

    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                String msg = ((TextMessage) message).getText();
                System.out.println("Message has been consumed : " + msg);
            } catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        } else {
            throw new IllegalArgumentException("Message Error");
        }
    }

    public Employee receiveMessage() throws JMSException {
        Map map = (Map) getJmsTemplate().receiveAndConvert();
        return new Employee((String) map.get("name"), (Integer) map.get("age"));
    }
}

我们已经了解了如何实现 MessageListener,下面是 Spring 应用上下文中的配置:

<bean id="messageListener" class="com.baeldung.spring.jms.SampleListener" /> 

<bean id="jmsContainer" 
  class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
    <property name="connectionFactory" ref="connectionFactory"/> 
    <property name="destinationName" ref="IN_QUEUE"/> 
    <property name="messageListener" ref="messageListener" /> 
</bean>

DefaultMessageListenerContainer 是 Spring 提供的默认消息监听容器,还有许多其他专门的容器。

8. 使用 Java 注解的基本配置

仅需使用 @JmsListener 注解,就可以将普通 bean 的一个方法转换为 JMS 听众端点。Spring JMS 提供了许多其他注解来简化 JMS 实现。

下面是一些带有注解的示例类:

@JmsListener(destination = "myDestination")
public void SampleJmsListenerMethod(Message<Order> order) { ... }

要在一个方法上添加多个监听器,只需添加多个 @JmsListener 注解。

为了支持带有 @JmsListener 注解的方法,我们需要在其中一个配置类中添加 @EnableJms 注解:

@Configuration
@EnableJms
public class AppConfig {

    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
        DefaultJmsListenerContainerFactory factory 
          = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory());
        return factory;
    }
}

9. 错误处理器

我们还可以为消息监听容器配置自定义错误处理器。

首先,实现 org.springframework.util.ErrorHandler 接口:

@Service
public class SampleJmsErrorHandler implements ErrorHandler {

    // ... logger

    @Override
    public void handleError(Throwable t) {
        LOG.warn("In default jms error handler...");
        LOG.error("Error Message : {}", t.getMessage());
    }

}

注意,我们重写了 handleError() 方法,它简单地记录错误消息。

然后,我们需要使用 setErrorHandler() 方法将我们的错误处理服务引用到 DefaultJmsListenerConnectionFactory

@Bean
public DefaultJmsListenerContainerFactorybjmsListenerContainerFactory() {
    DefaultJmsListenerContainerFactory factory 
      = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory());
    factory.setErrorHandler(sampleJmsErrorHandler);
    return factory;
}

这样,我们配置的错误处理器现在将捕获任何未处理的异常并记录消息。

如果愿意,我们也可以通过更新 appContext.xml 中的纯文本配置来配置错误处理器:

<bean id="sampleJmsErrorHandler"
  class="com.baeldung.spring.jms.SampleJmsErrorHandler" />

<bean id="jmsContainer"
  class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="destinationName" value="IN_QUEUE" />
    <property name="messageListener" ref="messageListener" />
    <property name="errorHandler" ref="sampleJmsErrorHandler" />
</bean>

10. 总结

本文讨论了 Spring JMS 的配置和基本概念,以及用于发送和接收消息的 Spring 特有的 JmsTemplate 类。

如往常一样,代码实现可在 GitHub 项目 中找到。


« 上一篇: WebJars入门介绍
» 下一篇: MapStruct 快速指南