領先一步
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 監聽器。