领先一步
VMware 提供培训和认证,助您加速进步。
了解更多Spring Framework 4.0 引入了一个新的 spring-messaging 模块,增加了 Spring Integration 的一系列类型,例如核心的 Message 抽象。Spring 4.1 将其 JMS 支持与之保持一致,以便您能够利用该抽象。但在深入研究之前,我想向您详细展示我们如何进一步改进监听器端点的基础设施。
您可能已经习惯了 <xyz:annotation-driven> 元素或 @Enable* 的对应项,并且可能一直在寻找 JMS 的类似功能。不用再找了:Spring 框架的下一个主要版本将允许您通过简单的注解来定义 JMS 监听器。
@Component
public class MyService {
@JmsListener(containerFactory = "myContainerFactory", destination = "myQueue")
public void processOrder(String data) { ... }
}
以下配置(忽略 JMS 基础设施设置)将在后台为 myQueue 目标创建一个 JMS 消息监听器容器,并在有可用消息时调用 processOrder。
@Configuration
@EnableJms
public class AppConfig {
@Bean
public DefaultJmsListenerContainerFactory myContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setDestinationResolver(destinationResolver());
factory.setConcurrency("3-10");
return factory;
}
}
这是使用 XML 命名空间的等效写法
<jms:annotation-driven/>
<bean id="myContainerFactory"
class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationResolver" ref="destinationResolver"/>
<property name="concurrency" value="3-10"/>
</bean>
和往常一样,@JmsListener 可以直接放在方法上,也可以通过元注解间接使用。该注解具有 jms:listener XML 元素在很长一段时间以来提供的常规选项。然而,containerFactory 是新的,它引用了 JmsListenerContainerFactory 的名称,这相当于您一直在 <jms:listener-container> 元素中配置的内容。
如果您想平滑地从现有配置迁移,我们在该元素中添加了一个 factory-id 属性。当存在该属性时,配置将自动作为该名称的 JmsListenerContainerFactory bean 公开。此 XML 配置等同于上面的 myJmsContainerFactory bean。
<jms:listener-container factory-id="myContainerFactory"
connection-factory="connectionFactory"
destination-resolver="destinationResolver"
concurrency="3-10"/>
由于单个容器工厂设置可能相当普遍,如果已设置或发现了默认的 containerFactory,则可以省略 containerFactory 属性。默认情况下,我们查找名为 jmsListenerContainerFactory 的 bean。
可以通过多种方式自定义此基础设施的配置,方法是实现 JmsListenerConfigurer 接口。正如我们刚才提到的,可以显式指定默认的容器工厂,但这个回调接口也允许您以编程方式注册 JMS 端点!
@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {
@Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
registrar.setDefaultContainerFactory(defaultContainerFactory());
SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
endpoint.setDestination("anotherQueue");
endpoint.setMessageListener(message -> {
// processing
});
registrar.registerEndpoint(endpoint);
}
@Bean
public DefaultJmsListenerContainerFactory defaultContainerFactory() {
...
}
上面的示例设置了默认的 JmsListenerContainerFactory,并且还在 anotherQueue 上配置了一个额外的端点。JmsListenerEndpoint 对您的端点进行建模,并负责为该模型配置容器。在上面的示例中,我们使用了 SimpleJmsListenerEndpoint,它提供了实际要调用的 MessageListener,但您也可以构建自己的端点变体来描述自定义调用机制。MethodJmsListenerEndpoint 是另一个示例,所有用 @JmsListener 注解的端点都使用它。
到目前为止,我们一直在向端点注入简单的 String,但它实际上可以有一个非常灵活的方法签名。让我们重写它以注入带有自定义头的 Order。
@Component
public class MyService {
@JmsListener(destination = "myQueue")
public void processOrder(Order order, @Header("order_type") String orderType) {
...
}
}
以下是您可以在 JMS 监听器端点中注入的主要元素:
javax.jms.Message 或其任何子类(前提是它匹配传入的消息类型)。javax.jms.Session,用于可选地访问原生 JMS API,例如发送自定义回复。org.springframework.messaging.Message,代表传入的 JMS 消息。请注意,此消息同时包含自定义头和标准头(由 JmsHeaders 定义)。@Header 注解的方法参数,用于提取特定的头值,包括标准 JMS 头。@Headers 注解的参数,它也必须可赋值给 java.util.Map,以便访问所有头。Message 和 Session),将被视为有效负载。您可以通过用 @Payload 注解参数来显式声明这一点。您还可以通过添加额外的 @Validated 来启用验证。能够注入 Spring 的 Message 抽象特别有助于利用存储在传输特定消息中的所有信息,而无需依赖传输特定的 API。
@JmsListener(destination = "myQueue")
public void processOrder(Message<Order> order) { ... }
这些功能在幕后为所有注解的元素提供。可以自定义验证和转换服务,甚至为您的自定义用例添加其他方法参数解析器。以下示例设置了一个自定义的 Validator,以便在调用监听器方法之前,先用它来验证用 @Validated 注解的有效负载。
@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {
@Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
registrar.setJmsHandlerMethodFactory(myJmsHandlerMethodFactory());
}
@Bean
public DefaultJmsHandlerMethodFactory myJmsHandlerMethodFactory() {
DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
factory.setValidator(myValidator());
return factory;
}
}
MessageListenerAdapter 中现有的支持已经允许您的方法具有非 void 返回类型。在这种情况下,调用结果将被封装在 javax.jms.Message 中,该消息将发送到原始消息的 JMSReplyTo 头中指定的目的地,或者发送到监听器上配置的默认目的地。现在可以使用消息传递抽象的 @SendTo 注解来设置这个默认目的地。
假设我们的 processOrder 方法现在应该返回一个 OrderStatus,可以这样编写以自动发送回复:
@JmsListener(destination = "myQueue")
@SendTo("queueOut")
public OrderStatus processOrder(Order order) {
// order processing
return status;
}
如果您需要以与传输无关的方式设置其他头,您可以返回一个 Message,例如:
@JmsListener(destination = "myQueue")
@SendTo("queueOut")
public Message<OrderStatus> processOrder(Order order) {
// order processing
return MessageBuilder
.withPayload(status)
.setHeader("code", 1234)
.build();
}
Spring Framework 4.1 预计于今年 7 月发布,其中包括 JMS 领域的几项改进:JMS 监听器方法可以简单地用注解来定义,并且可以使用非常灵活的方法签名。Spring 4.0 中引入的消息传递抽象现在也支持 JMS 监听器。