SpringBoot 禁用RabbitMQ自启动、设置RabbitMQ启动开关

您所在的位置:网站首页 电脑自动启动项目怎么关闭 SpringBoot 禁用RabbitMQ自启动、设置RabbitMQ启动开关

SpringBoot 禁用RabbitMQ自启动、设置RabbitMQ启动开关

2023-11-17 21:22| 来源: 网络整理| 查看: 265

一、需求背景

SpringBoot项目里使用了RabbitMQ,但某些场景下,不希望项目启动时自动检查RabbitMQ连接,例如:

场景1:在开发过程中,若RabbitMQ服务未启动,会导致SpringBoot项目启动失败。场景2:RabbitMQ做为系统里的一个插件功能,可能不同的客户部署环境中,并不需要启动RabbitMQ,但是要保证项目正常运行。

因此需要在项目里实现开关配置,可以动态的配置在项目启动时,是否自动启动RabbitMQ连接。

启动错误示例:

[2022-10-12 11:18:11.456] traceId= [RMI TCP Connection(8)-192.168.18.118] WARN o.s.boot.actuate.amqp.RabbitHealthIndicator - Rabbit health check failed org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:61) at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:602) at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:725) at org.springframework.amqp.rabbit.connection.ConnectionFactoryUtils.createConnection(ConnectionFactoryUtils.java:252) at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2173) at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2146) at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2126) at org.springframework.boot.actuate.amqp.RabbitHealthIndicator.getVersion(RabbitHealthIndicator.java:49) at org.springframework.boot.actuate.amqp.RabbitHealthIndicator.doHealthCheck(RabbitHealthIndicator.java:44) at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:82) at org.springframework.boot.actuate.health.HealthIndicator.getHealth(HealthIndicator.java:37) at org.springframework.boot.actuate.health.HealthEndpoint.getHealth(HealthEndpoint.java:77) at org.springframework.boot.actuate.health.HealthEndpoint.getHealth(HealthEndpoint.java:40) at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:130) at org.springframework.boot.actuate.health.HealthEndpointSupport.getAggregateContribution(HealthEndpointSupport.java:141) at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:126) at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:95) at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:66) at org.springframework.boot.actuate.health.HealthEndpoint.health(HealthEndpoint.java:71) at org.springframework.boot.actuate.health.HealthEndpoint.health(HealthEndpoint.java:61) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:74) at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:60) at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:122) at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:97) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468) at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) at sun.reflect.GeneratedMethodAccessor212.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357) at sun.rmi.transport.Transport$1.run(Transport.java:200) at sun.rmi.transport.Transport$1.run(Transport.java:197) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:196) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:81) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:476) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:218) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:200) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:162) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:394) at java.net.Socket.connect(Socket.java:606) at com.rabbitmq.client.impl.SocketFrameHandlerFactory.create(SocketFrameHandlerFactory.java:60) at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1223) at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1173) at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.connectAddresses(AbstractConnectionFactory.java:640) at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.connect(AbstractConnectionFactory.java:615) at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:565) ... 50 common frames omitted 二、实现方案 方案一、配置autoStartup环境变量,关闭自启动(不推荐)

在bootstrap.yml中配置:

spring: rabbitmq: listener: direct: auto-startup: false simple: auto-startup: false stream: auto-startup: false rabbitmq: start: false

在SpringBootApplicaiton启动类中配置:

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import javax.annotation.Resource; @SpringBootApplication public class TestServerApp { static Logger logger = LoggerFactory.getLogger(TestServerApp .class); public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(TestServerApp .class, args); RabbitMQStart rabbitMQRun = context.getBean(RabbitMQStart.class); rabbitMQRun.start(); } @Bean public RabbitMQStart rabbitMQRun() { return new RabbitMQStart(); } private static class RabbitMQStart { //为了在main中的static方法中使用@value注解只能用这种办法 @Value("${rabbitmq.start}") private Boolean rabbitmqStart; @Resource RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry; public void start() { if(rabbitmqStart) rabbitListenerEndpointRegistry.start(); else rabbitListenerEndpointRegistry.stop(); System.out.println("=================== Rabbitmq:"+rabbitmqStart+"==================="); } } }

缺点:

1、配置麻烦,而且不能放到Nacos配置中心

2、代码侵入多,需要改代码。

3、项目启动时,RabbitMQ仍会触发一次尝试连接,控制台会报错。

拓展:

1、autoStartup变量在RabbitMQ包中的位置:

org.springframework.boot.autoconfigure.amqp.RabbitProperties下的:

        org.springframework.boot.autoconfigure.amqp.RabbitProperties.BaseContainer下的:

                private boolean autoStartup = true;

2、三种container(有啥区别?还没研究~)

org.springframework.boot.autoconfigure.amqp.RabbitProperties.StreamContainer

org.springframework.boot.autoconfigure.amqp.RabbitProperties.DirectContainer

org.springframework.boot.autoconfigure.amqp.RabbitProperties.SimpleContainer(默认)

方案二、排除RabbitMQ的自动配置(不推荐)

在SpringBootApplication启动类上使用exclude排除

@SpringBootApplication(exclude = {RabbitAutoConfiguration.class})

或者在yaml中配置

spring: autoconfigure: exclude: org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

注意:SpringBoot加载AutoConfig的时机,要早于连接配置中心(比如Nacos),因此该yaml配置不能放到配置中心上的文件中,需要放在项目本地的bootstrap.yml或者application.yml中。

缺点:

1、不能放到Nacos配置中心,在bootstrap.yml中配置,在发布版本时会被一起打包发布。

2、若想恢复项目启动时,RabbitMQ自动初始化连接,在fat jar启动时必须指定运行参数来去掉该配置,若是用docker镜像运行则更麻烦,需要配置环境变量:

java -Dspring.autoconfigure.exclude=空 -jar app.jar

方案三、自定义RabbitMQ自动配置类(推荐)

自定义RabbitMQ的自动配置类(使用@Configuration)

import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; /** * @desccription 自定义RabbitMQ的启动配置类,可以通过配置变量来控制启用、禁用 * @auth [email protected] * @date 2022/10/12 */ @Configuration @ConditionalOnProperty("spring.rabbitmq.enable") public class MyRabbitAutoConfiguration extends RabbitAutoConfiguration { }

配置bootstrap.yal,排除默认的RabbitMQ自动配置类

spring: autoconfigure: exclude: org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

再配置RabbitMQ自动配置开关,此配置可以放在Nacos配置中心,因为使用的是@Configuration机制,而不是项目启动自动配置机制,因此读取开关配置的时机被延迟,可以等到读取配置中心完毕后再初始化RabbitMQ。

例如在nacos上配置rabbitmq.yml

spring: rabbitmq: #配置rabbitMq启用开关 enable: true host: 127.0.0.1 port: 5672 username: wsp password: bugaosuni virtual-host: /wsp



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3