Spring Boot 參考指南(訊息傳遞)

博弈發表於2019-01-19

32. 訊息傳遞

Spring框架為與訊息傳遞系統整合提供了廣泛的支援,從使用JmsTemplate簡化的JMS API到使用完整的基礎設施非同步接收訊息,Spring AMQP為高階訊息佇列協議提供了類似的特性集。Spring Boot還為RabbitTemplate和RabbitMQ提供自動配置選項,Spring WebSocket原生包括對STOMP訊息的支援,Spring Boot通過啟動器和少量的自動配置支援這一點,Spring Boot還支援Apache Kafka。

32.1 JMS

javax.jms.ConnectionFactory介面提供了建立javax.jms.Connection與JMS代理互動的標準方法,儘管Spring需要一個ConnectionFactory來處理JMS,你通常不需要自己直接使用它,而是可以依賴於更高階別的訊息傳遞抽象。(詳見Spring Framework參考文件的相關部分。)Spring Boot還自動配置傳送和接收訊息所需的基礎設施。

32.1.1 ActiveMQ支援

ActiveMQ在類路徑上可用時,Spring Boot還可以配置ConnectionFactory,如果代理存在,則會自動啟動和配置嵌入式代理(只要沒有通過配置指定代理URL)。

如果你使用spring-boot-starter-activemq,那麼將提供連線或嵌入ActiveMQ例項所需的依賴項,與JMS整合的Spring基礎設施也是一樣。

ActiveMQ配置由在spring.activemq.*中的外部配置屬性控制,例如,你可以在application.properties中宣告以下部分:

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

你還可以通過向org.apache.activemq:activemq-pool新增一個依賴項來共享JMS資源並相應地配置PooledConnectionFactory,如下例所示:

spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50

有關更多支援的選項,請參見ActiveMQProperties,你還可以註冊一個任意數量的實現activemqconnectionfactorycustomzer的bean進行更高階的自定義。

預設情況下,ActiveMQ建立一個目的地,如果它還不存在,那麼目的地將根據它們提供的名稱解析。

32.1.2 Artemis支援

Spring Boot可以自動配置ConnectionFactory,當它檢測到在類路徑上可用的Artemis時,如果代理存在,則自動啟動和配置嵌入式代理(除非模式屬性已顯式設定),所支援的模式是embedded(要明確地說明需要一個嵌入式代理,如果代理在類路徑上不可用,就會出現錯誤)和native(使用netty傳輸協議連線到代理),在配置後者時,Spring Boot使用預設設定配置連線到執行在本地機器上的代理的ConnectionFactory

如果你使用spring-boot-starter-artemis,則提供了連線到現有的Artemis例項的必要依賴項,以及與JMS整合的Spring基礎設施,新增org.apache.activemq:artemis-jms-server到你的應用程式以允許你使用嵌入式模式。

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

spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret

在嵌入代理時,你可以選擇是否啟用永續性,並列出應該可用的目的地,可以將它們指定為逗號分隔的列表,以使用預設選項建立它們,或者可以定義型別為org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration的bean,分別用於高階佇列和主題配置。

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

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

32.1.3 使用JNDI ConnectionFactory

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

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

32.1.4 傳送訊息

Spring的JmsTemplate是自動配置的,你可以將其自動連線到你自己的bean中,如下面的示例所示:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final JmsTemplate jmsTemplate;

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

    // ...

}

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

32.1.5 接收訊息

當出現JMS基礎設施時,可以使用@JmsListener註解任何bean,以建立監聽器端點,如果沒有定義JmsListenerContainerFactory,則會自動配置預設工廠,如果定義了DestinationResolverMessageConverter bean,則它將自動關聯到預設工廠。

預設情況下,預設工廠是事務性的,如果你執行的基礎設施中存在JtaTransactionManager,那麼它預設與偵聽器容器相關聯,如果沒有,則啟用sessionTransacted標誌。在後一個場景中,你可以通過在監聽器方法(或委託)上新增@Transactional,將本地資料儲存事務與接收訊息的處理相關聯,這確保在本地事務完成之後,傳入訊息得到確認,這還包括髮送在相同JMS會話上執行的響應訊息。

以下元件在someQueue目的地上建立監聽器端點:

@Component
public class MyBean {

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

}

有關更多細節,請參見@EnableJms的Javadoc

如果你需要建立更多的JmsListenerContainerFactory例項,或者希望重寫預設的例項,Spring Boot提供了一個DefaultJmsListenerContainerFactoryConfigurer,你可以使用它來初始化一個DefaultJmsListenerContainerFactory,其設定與自動配置的工廠相同。

例如,下面的示例公開了另一個使用特定MessageConverter的工廠:

@Configuration
static class JmsConfiguration {

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

}

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

32.2 AMQP

高階訊息佇列協議(AMQP)是面向訊息的中介軟體的一種平臺無關的、有線級別的協議。Spring AMQP專案將核心Spring概念應用於基於AMQP的訊息傳遞解決方案的開發,Spring Boot為通過RabbitMQ使用AMQP提供了一些方便,包括spring-boot-starter-amqp“啟動器”。

32.2.1 RabbitMQ支援

RabbitMQ是一個輕量級的、可靠的、可伸縮的、可移植的訊息代理,基於AMQP協議,Spring使用RabbitMQ通過AMQP協議進行通訊。

RabbitMQ配置由spring.rabbitmq.*的外部配置屬性控制,例如,你可以在application.properties中宣告以下部分:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

如果上下文中存在ConnectionNameStrategy bean,那麼它將自動用於命名由自動配置的ConnectionFactory建立的連線。有關更多受支援的選項,請參閱RabbitProperties

有關詳細資訊,請參閱RabbitMQ使用的協議AMQP

32.2.2 傳送訊息

Spring的AmqpTemplateAmqpAdmin是自動配置的,你可以將它們自動連線到你自己的bean中,如下面的示例所示:

import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final AmqpAdmin amqpAdmin;
    private final AmqpTemplate amqpTemplate;

    @Autowired
    public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
        this.amqpAdmin = amqpAdmin;
        this.amqpTemplate = amqpTemplate;
    }

    // ...

}

RabbitMessagingTemplate可以以類似的方式注入,如果定義了MessageConverter bean,它會自動關聯到自動配置的AmqpTemplate

如果有必要,任何定義為bean的org.springframework.amqp.core.Queue自動用於在RabbitMQ例項上宣告相應的佇列。

重試操作,可以對AmqpTemplate啟用重試(例如,如果代理連線丟失了),預設情況下禁用重試。

32.2.3 接收訊息

當Rabbit基礎設施存在時,可以使用@RabbitListener對任何bean進行註解,以建立監聽器端點,如果沒有定義RabbitListenerContainerFactory,則會自動配置預設的SimpleRabbitListenerContainerFactory,你可以使用spring.rabbitmq.listener.type屬性切換到直接容器。如果定義了MessageConverterMessageRecoverer bean,則它將自動與預設工廠相關聯。

以下示例元件在someQueue佇列上建立監聽器端點:

@Component
public class MyBean {

    @RabbitListener(queues = "someQueue")
    public void processMessage(String content) {
        // ...
    }

}

有關更多細節,請參見@EnableRabbit的Javadoc

如果你需要建立更多的RabbitListenerContainerFactory例項,或者你想要覆蓋預設值,Spring Boot提供了一個SimpleRabbitListenerContainerFactoryConfigurer和一個DirectRabbitListenerContainerFactoryConfigurer,你可以使用它們初始化一個SimpleRabbitListenerContainerFactory,以及一個DirectRabbitListenerContainerFactory,其設定與自動配置使用的工廠相同。

選擇哪種容器型別並不重要,這兩個bean通過自動配置公開。

例如,下面的configuration類公開另一個使用特定MessageConverter的工廠:

@Configuration
static class RabbitConfiguration {

    @Bean
    public SimpleRabbitListenerContainerFactory myFactory(
            SimpleRabbitListenerContainerFactoryConfigurer configurer) {
        SimpleRabbitListenerContainerFactory factory =
                new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然後你可以在任何@RabbitListener註解的方法中使用工廠,如下所示:

@Component
public class MyBean {

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

}

你可以啟用重試來處理監聽器丟擲異常的情況,預設情況下,使用RejectAndDontRequeueRecoverer,但是可以定義自己的MessageRecoverer,當重試結束時,訊息將被拒絕,如果將代理配置為這樣做,則訊息將被刪除或路由到死信交換,預設情況下,重試被禁用。

重要
預設情況下,如果重試被禁用並且監聽器丟擲異常,該遞送被無限期地重試,你可以用兩種方式修改此行為:將defaultRequeueRejected屬性設定為false,以便嘗試零重複傳送,或者丟擲AmqpRejectAndDontRequeueException來通知訊息應該被拒絕,後者是在啟用重試並達到最大提交嘗試次數時使用的機制。

32.3 Apache Kafka支援

通過提供spring-kafka專案的自動配置來支援Apache Kafka

Kafka配置由spring.kafka.*中的外部配置屬性控制,例如,你可以在application.properties中宣告以下部分:

spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup

要在啟動時建立主題,請新增一個型別NewTopic的bean,如果主題已經存在,則忽略bean。

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

32.3.1 傳送訊息

Spring的KafkaTemplate是自動配置的,你可以直接在你自己的bean中自動連線它,如下面的示例所示:

@Component
public class MyBean {

    private final KafkaTemplate kafkaTemplate;

    @Autowired
    public MyBean(KafkaTemplate kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    // ...

}

如果定義了一個RecordMessageConverter bean,它將自動關聯到自動配置的KafkaTemplate

32.3.2 接收訊息

當存在Apache Kafka基礎設施時,任何bean都可以使用@KafkaListener進行註解,以建立監聽器端點,如果沒有定義KafkaListenerContainerFactory,預設設定為使用spring.kafka.listener.*中定義的鍵,此外,如果定義了一個RecordMessageConverter bean,它將自動關聯到預設的工廠。

@Component
public class MyBean {

    @KafkaListener(topics = "someTopic")
    public void processMessage(String content) {
        // ...
    }

}

32.3.3 附加的Kafka屬性

自動配置所支援的屬性顯示在附錄A中,通用的應用程式屬性。注意,在大多數情況下,這些屬性(連字元或駝峰式大小寫)直接對映到Apache Kafka *屬性,有關詳細資訊,請參閱Apache Kafka文件。

前幾個屬性同時適用於生產者和消費者,但是如果你希望對每個屬性使用不同的值,可以在生產者或消費者級別指定,Apache Kafka設計具有高、中或低重要性的屬性,Spring Boot自動配置支援所有重要屬性、一些選定的中屬性和低屬性,以及任何沒有預設值的屬性。

Kafka支援的屬性中只有一部分是可以通過KafkaProperties類獲得的,如果你希望為生產者或消費者配置不受直接支援的其他屬性,請使用以下屬性:

spring.kafka.properties.prop.one=first
spring.kafka.admin.properties.prop.two=second
spring.kafka.consumer.properties.prop.three=third
spring.kafka.producer.properties.prop.four=fourth

這將設定通用的prop.oneKafka屬性為first(適用於生產者、消費者和管理員),prop.two 管理員屬性為secondprop.three消費者屬性為third並且prop.four生產者屬性為fourth

你還可以配置Spring Kafka JsonDeserializer,如下所示:

spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.value.default.type=com.example.Invoice
spring.kafka.consumer.properties.spring.json.trusted.packages=com.example,org.acme

同樣,可以禁用JsonSerializer在header中傳送型別資訊的預設行為:

spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.producer.properties.spring.json.add.type.headers=false

以這種方式設定的屬性將覆蓋Spring Boot顯式支援的任何配置項。


下一篇:使用RestTemplate呼叫REST服務

相關文章