Spring boot使用Rabbitmq注解

三個(gè)注解:

@EnableRabbit
@RabbitListener
@RabbitHandler

@EnableRabbit

@EnableRabbit和@Configuration一起使用,可以加在類或者方法上,這個(gè)注解開啟了容器對(duì)注冊(cè)的bean的@RabbitListener檢查。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RabbitBootstrapConfiguration.class)
public @interface EnableRabbit {
}

從源代碼上可以看出這個(gè)注解提供了很簡(jiǎn)單的功能就是引入了另一個(gè)配置類:RabbitBootstrapConfiguration。該類注冊(cè)了兩個(gè)bean:一個(gè)BeanPostProcessor一個(gè)ListenerEndpointRegistry。

注冊(cè)的BeanPostProcessor則會(huì)在bean初始化之后掃描@RabbitListener和@RabbitHandler注解。

@Configuration
public class RabbitBootstrapConfiguration {

    @Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
        return new RabbitListenerAnnotationBeanPostProcessor();
    }

    @Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)
    public RabbitListenerEndpointRegistry defaultRabbitListenerEndpointRegistry() {
        return new RabbitListenerEndpointRegistry();
    }

}

@RabbitListener

@RabbitListener用于注冊(cè)Listener時(shí)使用的信息:如queue,exchange,key、ListenerContainerFactory和RabbitAdmin的bean name。

@RabbitListener(containerFactory = "rabbitListenerContainerFactory", bindings = @QueueBinding(
        value = @Queue(value = "${mq.config.queue}", durable = "true"),
        exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.TOPIC),
        key = "${mq.config.key}"), admin = "rabbitAdmin")

掃描到bean帶有該注解后,首先會(huì)將注解的內(nèi)容封裝到Endpoint對(duì)象中并和ListenerContainerFactory的實(shí)例一起添加到上面的RabbitListenerEndpointRegistry實(shí)例中。添加的時(shí)候會(huì)創(chuàng)建相應(yīng)的ListenerContainer實(shí)例并添加Listener對(duì)象。

RabbitListenerAnnotationBeanPostProcessor通過RabbitListenerEndpointRegistrar間接持有RabbitListenerEndpointRegistry實(shí)例。

@RabbitHandler

@RabbitListener 和 @RabbitHandler結(jié)合使用,不同類型的消息使用不同的方法來處理。

public class CommandListener{

    @RabbitHandler
    public void handler1(ApiMessage msg){
        System.out.println(msg);
    }

    @RabbitHandler
    public void handler2(Map msg){
        System.out.println(msg);
    }
}

可能遇到的問題

AMQP錯(cuò)誤:ACCESS_REFUSED

Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=403, reply-text=ACCESS_REFUSED - operation not permitted on the default exchange, class-id=50, method-id=20)

出現(xiàn)這個(gè)問題的原因是因?yàn)長(zhǎng)istenContainer的auto-declare默認(rèn)為true,container會(huì)使用RabbitAdmin去重新聲明Queue、Exchange、Binding等對(duì)象。如果沒有配置RabbitAdmin則會(huì)報(bào)ACCESS_REFUSED的錯(cuò)誤,看官方解釋:

Starting with version 1.4, SimpleMessageListenerContainer has this new property.
When set to true (default), the container will use a RabbitAdmin to redeclare all AMQP objects (Queues, Exchanges, Bindings), if it detects that at least one of its queues is missing during startup, perhaps because it’s an auto-delete or an expired queue, but the redeclaration will proceed if the queue is missing for any reason. To disable this behavior, set this property to false. Note that the container will fail to start if all of its queues are missing.

在spring-boot中,使用@EnableRabbit,需要在context添加ListenerContainerFactory。但是ListenerContainerFactory沒有提供設(shè)置container的autoDeclare屬性的接口,也沒辦法為L(zhǎng)istenerContainer實(shí)例注入RabbitAdmin實(shí)例。

解決方案是為@RabbitListener指定RabbitAdmin實(shí)例的bean name

@RabbitListener(containerFactory = "rabbitListenerContainerFactory", bindings = @QueueBinding(
        value = @Queue(value = "${mq.config.queue}", durable = "true"),
        exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.TOPIC),
        key = "${mq.config.key}"), admin = "rabbitAdmin")
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容