JMS

ConnectionFactory 介面提供了一種標準方法來建立 Connection 以與 JMS 代理互動。儘管 Spring 需要一個 ConnectionFactory 來使用 JMS,但您通常無需自己直接使用它,而是可以依賴更高級別的訊息抽象。(有關詳細資訊,請參閱 Spring Framework 參考文件的相關部分。)Spring Boot 也自動配置了傳送和接收訊息所需的基礎設施。

ActiveMQ "Classic" 支援

當類路徑中存在 ActiveMQ "Classic" 時,Spring Boot 可以配置一個 ConnectionFactory。如果存在代理,則會自動啟動並配置一個嵌入式代理(前提是沒有透過配置指定代理 URL 且在配置中沒有停用嵌入式代理)。

如果您使用 spring-boot-starter-activemq,則會提供連線到 ActiveMQ "Classic" 例項所需的依賴項,以及與 JMS 整合的 Spring 基礎設施。將 org.apache.activemq:activemq-broker 新增到您的應用程式中,即可使用嵌入式代理。

ActiveMQ "Classic" 的配置由 spring.activemq.* 中的外部配置屬性控制。

如果類路徑中有 activemq-broker,則 ActiveMQ "Classic" 會被自動配置為使用 VM transport,這會在同一個 JVM 例項中啟動一個嵌入式代理。

您可以透過配置 spring.activemq.embedded.enabled 屬性來停用嵌入式代理,如下例所示

  • 屬性

  • YAML

spring.activemq.embedded.enabled=false
spring:
  activemq:
    embedded:
      enabled: false

如果您配置了代理 URL,嵌入式代理也將被停用,如下例所示

  • 屬性

  • YAML

spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
spring:
  activemq:
    broker-url: "tcp://192.168.1.210:9876"
    user: "admin"
    password: "secret"

如果您想完全控制嵌入式代理,請參閱ActiveMQ "Classic" 文件以獲取更多資訊。

預設情況下,一個 CachingConnectionFactory 會包裝原生 ConnectionFactory,並使用可透過 spring.jms.* 中的外部配置屬性控制的合理設定。

  • 屬性

  • YAML

spring.jms.cache.session-cache-size=5
spring:
  jms:
    cache:
      session-cache-size: 5

如果您寧願使用原生連線池,可以透過新增 org.messaginghub:pooled-jms 依賴並相應地配置 JmsPoolConnectionFactory 來實現,如下例所示

  • 屬性

  • YAML

spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
spring:
  activemq:
    pool:
      enabled: true
      max-connections: 50
有關更多支援的選項,請參閱 ActiveMQProperties。您還可以註冊任意數量實現 ActiveMQConnectionFactoryCustomizer 介面的 Bean,以進行更高階的自定義。

預設情況下,如果目的地尚不存在,ActiveMQ "Classic" 會建立它,這樣目的地就可以根據其提供的名稱進行解析。

ActiveMQ Artemis 支援

當 Spring Boot 檢測到類路徑中存在 ActiveMQ Artemis 時,它可以自動配置一個 ConnectionFactory。如果存在代理,則會自動啟動並配置一個嵌入式代理(除非明確設定了 mode 屬性)。支援的模式包括 embedded(明確表示需要嵌入式代理,如果代理不在類路徑中應報告錯誤)和 native(使用 netty 傳輸協議連線到代理)。配置後一種模式時,Spring Boot 會配置一個 ConnectionFactory,該工廠使用預設設定連線到在本地機器上執行的代理。

如果您使用 spring-boot-starter-artemis,則會提供連線到現有 ActiveMQ Artemis 例項所需的依賴項,以及與 JMS 整合的 Spring 基礎設施。將 org.apache.activemq:artemis-jakarta-server 新增到您的應用程式中,即可使用嵌入式模式。

ActiveMQ Artemis 的配置由 spring.artemis.* 中的外部配置屬性控制。例如,您可以在 application.properties 中宣告以下部分

  • 屬性

  • YAML

spring.artemis.mode=native
spring.artemis.broker-url=tcp://192.168.1.210:9876
spring.artemis.user=admin
spring.artemis.password=secret
spring:
  artemis:
    mode: native
    broker-url: "tcp://192.168.1.210:9876"
    user: "admin"
    password: "secret"

在嵌入式代理模式下,您可以選擇是否啟用持久化,並列出應可用的目的地。這些目的地可以指定為逗號分隔的列表,以使用預設選項建立它們,或者您可以定義型別為 JMSQueueConfigurationTopicConfiguration 的 Bean,分別用於高階佇列和主題配置。

預設情況下,一個 CachingConnectionFactory 會包裝原生 ConnectionFactory,並使用可透過 spring.jms.* 中的外部配置屬性控制的合理設定。

  • 屬性

  • YAML

spring.jms.cache.session-cache-size=5
spring:
  jms:
    cache:
      session-cache-size: 5

如果您寧願使用原生連線池,可以透過新增 org.messaginghub:pooled-jms 依賴並相應地配置 JmsPoolConnectionFactory 來實現,如下例所示

  • 屬性

  • YAML

spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50
spring:
  artemis:
    pool:
      enabled: true
      max-connections: 50

有關更多支援的選項,請參閱 ArtemisProperties

不涉及 JNDI 查詢,目的地根據其名稱進行解析,可以使用 ActiveMQ Artemis 配置中的 name 屬性或透過配置提供的名稱。

使用 JNDI ConnectionFactory

如果您在應用程式伺服器中執行您的應用程式,Spring Boot 會嘗試使用 JNDI 查詢 JMS ConnectionFactory。預設情況下,會檢查 java:/JmsXAjava:/XAConnectionFactory 位置。如果需要指定其他位置,您可以使用 spring.jms.jndi-name 屬性,如下例所示

  • 屬性

  • YAML

spring.jms.jndi-name=java:/MyConnectionFactory
spring:
  jms:
    jndi-name: "java:/MyConnectionFactory"

傳送訊息

Spring 的 JmsTemplate 會自動配置,您可以直接將其自動注入到您的 Bean 中,如下例所示

  • Java

  • Kotlin

import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	private final JmsTemplate jmsTemplate;

	public MyBean(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	// ...

	public void someMethod() {
		this.jmsTemplate.convertAndSend("hello");
	}

}
import org.springframework.jms.core.JmsTemplate
import org.springframework.stereotype.Component

@Component
class MyBean(private val jmsTemplate: JmsTemplate) {

	// ...

	fun someMethod() {
		jmsTemplate.convertAndSend("hello")
	}

}
JmsMessagingTemplate 可以以類似的方式注入。如果定義了 DestinationResolverMessageConverter Bean,它們將自動關聯到自動配置的 JmsTemplate

接收訊息

當存在 JMS 基礎設施時,任何 Bean 都可以使用 @JmsListener 註解來建立監聽器端點。如果沒有定義 JmsListenerContainerFactory,則會自動配置一個預設的工廠。如果定義了 DestinationResolverMessageConverterExceptionListener Bean,它們將自動關聯到預設工廠。

在大多數情況下,訊息監聽器容器應該配置針對原生的 ConnectionFactory。這樣每個監聽器容器都有自己的連線,並且在本地恢復方面擁有完全的責任。自動配置使用 ConnectionFactoryUnwrapper 來從自動配置的工廠中解包出原生連線工廠。

自動配置只解包 CachedConnectionFactory

預設情況下,預設工廠是事務性的。如果您在存在 JtaTransactionManager 的基礎設施中執行,它會預設與監聽器容器關聯。如果沒有,則啟用 sessionTransacted 標誌。在後一種情況下,您可以透過在監聽器方法(或其委託方法)上新增 @Transactional 來將本地資料儲存事務與處理傳入訊息關聯起來。這確保在本地事務完成後,傳入訊息被確認。這也包括髮送在同一 JMS 會話上執行的響應訊息。

以下元件在 someQueue 目的地建立了一個監聽器端點

  • Java

  • Kotlin

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	@JmsListener(destination = "someQueue")
	public void processMessage(String content) {
		// ...
	}

}
import org.springframework.jms.annotation.JmsListener
import org.springframework.stereotype.Component

@Component
class MyBean {

	@JmsListener(destination = "someQueue")
	fun processMessage(content: String?) {
		// ...
	}

}
有關更多詳細資訊,請參閱 @EnableJms API 文件。

如果您需要建立更多 JmsListenerContainerFactory 例項或想覆蓋預設設定,Spring Boot 提供了一個 DefaultJmsListenerContainerFactoryConfigurer,您可以使用它來初始化一個 DefaultJmsListenerContainerFactory,使其具有與自動配置的工廠相同的設定。

例如,以下示例展示了使用特定 MessageConverter 的另一個工廠

  • Java

  • Kotlin

import jakarta.jms.ConnectionFactory;

import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.boot.jms.ConnectionFactoryUnwrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;

@Configuration(proxyBeanMethods = false)
public class MyJmsConfiguration {

	@Bean
	public DefaultJmsListenerContainerFactory myFactory(DefaultJmsListenerContainerFactoryConfigurer configurer,
			ConnectionFactory connectionFactory) {
		DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
		configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory));
		factory.setMessageConverter(new MyMessageConverter());
		return factory;
	}

}
import jakarta.jms.ConnectionFactory
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer
import org.springframework.boot.jms.ConnectionFactoryUnwrapper
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.jms.config.DefaultJmsListenerContainerFactory

@Configuration(proxyBeanMethods = false)
class MyJmsConfiguration {

	@Bean
	fun myFactory(configurer: DefaultJmsListenerContainerFactoryConfigurer,
				  connectionFactory: ConnectionFactory): DefaultJmsListenerContainerFactory {
		val factory = DefaultJmsListenerContainerFactory()
		configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory))
		factory.setMessageConverter(MyMessageConverter())
		return factory
	}

}
在上面的示例中,定製使用了 ConnectionFactoryUnwrapper,以與自動配置工廠相同的方式將原生連線工廠關聯到訊息監聽器容器。

然後您可以在任何帶有 @JmsListener 註解的方法中使用該工廠,如下所示

  • Java

  • Kotlin

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	@JmsListener(destination = "someQueue", containerFactory = "myFactory")
	public void processMessage(String content) {
		// ...
	}

}
import org.springframework.jms.annotation.JmsListener
import org.springframework.stereotype.Component

@Component
class MyBean {

	@JmsListener(destination = "someQueue", containerFactory = "myFactory")
	fun processMessage(content: String?) {
		// ...
	}

}