領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多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,例如傳送自定義回覆。org.springframework.messaging.Message
。請注意,此訊息包含自定義頭和標準頭(由 JmsHeaders
定義)。@Header
註解的方法引數,用於提取特定的頭部值,包括標準 JMS 頭部。@Headers
註解的引數,該引數也必須可以賦值給 java.util.Map
以獲取所有頭部。Message
和 Session
),則被視為有效載荷(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 監聽器了。