springboot-rabbitmq 实现动态配置监听容器

1.从源码了解mq启动配置流程

1.1配置启动入口

1.1.1从factories我们可以看到mq的启动配置类
在这里插入图片描述

1.1.2然后我们找到 RabbitAutoConfiguration,发现它引入了RabbitAnnotationDrivenConfiguration这个配置类

@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}

1.1.3进入RabbitAnnotationDrivenConfiguration滑到最低部看到这里引入了@EnableRabbit这个注解,找个注解里面又引出RabbitBootstrapConfiguration这个配置类

@EnableRabbit
@ConditionalOnMissingBean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
protected static class EnableRabbitConfiguration {

}

//---------------------------------------------


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

1.1.4这里定义了两个bean,其中RabbitListenerEndpointRegistry就是监听容器的注册操作实现类

@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();
	}

}

1.1.5RabbitListenerEndpointRegistry里面有获取所有容器的方法getListenerContainerIds和注册监听容器的方法registerListenerContainer


	/**
	 * Create a message listener container for the given {@link RabbitListenerEndpoint}.
	 * <p>This create the necessary infrastructure to honor that endpoint
	 * with regards to its configuration.
	 * @param endpoint the endpoint to add
	 * @param factory the listener factory to use
	 * @see #registerListenerContainer(RabbitListenerEndpoint, RabbitListenerContainerFactory, boolean)
	 */
	public void registerListenerContainer(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory) {
		registerListenerContainer(endpoint, factory, false);
	}

1.1.6触发监听容器的位置是在RabbitListenerEndpointRegistrar类里面的bean初始化完成调用的钩子方法里面,注册所有listenercontain。ps:而RabbitListenerEndpointRegistrar类是RabbitListenerAnnotationBeanPostProcessor的属性对象,RabbitListenerAnnotationBeanPostProcessor是在1.1.4哪里初始化的rabbitmq监听注解拓展对象

	@Override
	public void afterPropertiesSet() {
		registerAllEndpoints();
	}


//---------------------------------------
public class RabbitListenerAnnotationBeanPostProcessor
		implements BeanPostProcessor, Ordered, BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware,
		SmartInitializingSingleton {

	/**
	 * The bean name of the default {@link org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory}.
	 */
	public static final String DEFAULT_RABBIT_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "rabbitListenerContainerFactory";


	private final RabbitListenerEndpointRegistrar registrar = new RabbitListenerEndpointRegistrar();
}

2.创建自定义消息处理对象和监听容器

2.1在自定义bean引入RabbitListenerEndpointRegistry

@Component
public class RabbitmqCustomerConfiguration {
    
    @Resource
    RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
    
 
}

2.2创建MyMessageListener类,实现消息监听接口


@Component
public class MyMessageListener implements  MessageListener {


    @Override
    public void onMessage(Message message) {
        System.out.println(new String(message.getBody()));

    }
}

2.3新建SimpleRabbitListenerEndpoint,设置需要监听的队列名和自定义消息接收处理器


@Component
public class RabbitmqCustomerConfiguration {

    @Resource
    RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;

    @Autowired
    MyMessageListener myMessageListener;

    public void registryCustomerContain() {
        SimpleRabbitListenerEndpoint simpleRabbitListenerEndpoint = new SimpleRabbitListenerEndpoint();
        simpleRabbitListenerEndpoint.setMessageListener(myMessageListener);
        simpleRabbitListenerEndpoint.setQueueNames("testQueue");
        
		//第三个参数是否马上启动监听容器        
		rabbitListenerEndpointRegistry.registerListenerContainer(simpleRabbitListenerEndpoint,null,true);


    }

}

ps:第二个参数的null为空的时候会调用default的factory。
从RabbitListenerEndpointRegistrar判断工厂是否为空,最后会根据containerFactoryBeanName获取

	private RabbitListenerContainerFactory<?> resolveContainerFactory(AmqpListenerEndpointDescriptor descriptor) {
		if (descriptor.containerFactory != null) 
		//*return descriptor.containerFactory;
		}
		else if (this.containerFactory != null) {
			//*	return this.containerFactory;
		}
		else if (this.containerFactoryBeanName != null) {
			Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
			this.containerFactory = this.beanFactory.getBean(
					this.containerFactoryBeanName, RabbitListenerContainerFactory.class);
			return this.containerFactory;  // Consider changing this if live change of the factory is required
		}
		else {
			throw new IllegalStateException("Could not resolve the " +
					RabbitListenerContainerFactory.class.getSimpleName() + " to use for [" +
					descriptor.endpoint + "] no factory was given and no default is set.");
		}
	}

而containerFactoryBeanName是来自RabbitListenerAnnotationBeanPostProcessor的

public static final String DEFAULT_RABBIT_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "rabbitListenerContainerFactory";

也就是1.1.2里面提到的RabbitAnnotationDrivenConfiguration里面定义的bean

	@Bean
	@ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
	public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
			SimpleRabbitListenerContainerFactoryConfigurer configurer,
			ConnectionFactory connectionFactory) {
		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
		configurer.configure(factory, connectionFactory);
		return factory;
	}

2.4思路:运行rabbitListenerEndpointRegistry的stop和start重启刷新所有监听器,或者刷新容器会导致刷新

	@Override
	public void start() {
		for (MessageListenerContainer listenerContainer : getListenerContainers()) {
			startIfNecessary(listenerContainer);
		}
	}



//----------------

	private void startIfNecessary(MessageListenerContainer listenerContainer) {
		if (this.contextRefreshed || listenerContainer.isAutoStartup()) {
			listenerContainer.start();
		}
	}

//----------------


	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		if (event.getApplicationContext().equals(this.applicationContext)) {
			this.contextRefreshed = true;
		}
	}
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot是一种流行的Java框架,它会自动配置常用的组件,以简化开发,提高生产力。与此同时,RabbitMQ是一个广泛使用的开源消息队列,它被广泛应用于各种场景下的异步通信、任务调度等业务场景。那么,如何将Spring BootRabbitMQ整合在一起呢? 首先,需要在pom.xml文件中引入Spring AMQP相关的依赖包,这些包会提供Spring Boot整合RabbitMQ所需的基本组件,例如RabbitTemplate、ConnectionFactory、RabbitAdmin等。其次,需要在项目配置文件中,添加RabbitMQ的连接信息,例如用户名、密码、IP地址、端口号等。当然,如果使用云服务或Docker容器,连接信息也需单独配置。 接着,需要定义消息发送者和消息接收者。发送者需要注入RabbitTemplate,通过其中的convertAndSend方法发送消息;接收者则需要定义一个监听队列,并通过@RabbitListener注解绑定方法处理该队列中的消息。当然,这些注解都需要在类上使用@EnableRabbit注解进行开启。 最后,测试与Debug是必不可少的环节,测试过程中可以使用RabbitMQ的web管理界面对队列进行查看、修改、删除等操作,以验证代码的正确性和消息的发送接收。 综上,Spring BootRabbitMQ的整合相对简单,只需进行一些基本的配置和注解即可实现异步通信。但在实际业务场景下,还需要进一步考虑如何保证消息的稳定性、重试机制、消息确认等因素,以确保消息的可靠性和安全性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值