Spring 4.1 即將推出的 JMS 改進

工程 | Stéphane Nicoll | 2014 年 4 月 30 日 | ...

Spring Framework 4.0 引入了一個新的 spring-messaging 模組,添加了一系列 Spring Integration 型別,例如核心的 Message 抽象。Spring 4.1 調整了其 JMS 支援,以便您可以從該抽象中受益。但在深入探討之前,我想向您詳細展示我們如何進一步改進了監聽器端點基礎設施。

註解驅動的監聽器端點

您可能習慣了 <xyz:annotation-driven> 元素或 @Enable* 對應項,或許您一直在尋找 JMS 的類似功能。現在就不用再找了:Spring framework 的下一個主要版本將允許您使用簡單的註解來定義 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 屬性。預設情況下,我們會查詢名為 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,例如傳送自定義回覆。
  • 表示接收到的 JMS 訊息的 org.springframework.messaging.Message。請注意,此訊息包含自定義頭和標準頭(由 JmsHeaders 定義)。
  • 使用 @Header 註解的方法引數,用於提取特定的頭部值,包括標準 JMS 頭部。
  • 使用 @Headers 註解的引數,該引數也必須可以賦值給 java.util.Map 以獲取所有頭部。
  • 未註解的元素,如果不是支援的型別之一(即 MessageSession),則被視為有效載荷(payload)。您可以透過使用 @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 定於今年七月釋出,並在 JMS 領域包含了多項改進:JMS 監聽器方法可以簡單地使用註解,並且可以使用非常靈活的方法簽名。Spring 4.0 中引入的訊息抽象現在也支援 JMS 監聽器了。

獲取 Spring 新聞稿

訂閱 Spring 新聞稿以保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲取支援

Tanzu Spring 透過一個簡單的訂閱提供對 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群即將舉行的所有活動。

檢視全部