1、现象
项目在运行时,rocketMQ是能正常发送消息,但是今天在上线的过程中,出现了rocketMQ发送失败的情况,具体报错如下
org.apache.rocketmq.client.exception.MQClientException:The producer service state not OK, CREATE_JUST
2、分析
首先我们来看一下rocketMQ的producer生成bean的代码
@Bean(value = "pushSegmentProducer")
@Primary
public DefaultMQProducer pushSegmentProducer() {
DefaultMQProducer producer = new DefaultMQProducer(rocketMQProducerConfigs.getPushSegmentProducerConfig().getGroupName(),
producerAclRpcHook(rocketMQProducerConfigs.getPushSegmentProducerConfig()));
producer.setInstanceName("push_segment_producer" + rocketMQConsumerConfigs.getPushSegmentConsumerConfig().getGroupName());
producer.setNamesrvAddr(rocketMQProducerConfigs.getPushSegmentProducerConfig().getNamesrvAddr());
LOGGER.info("rocketmq producer started. groupName:{}", rocketMQProducerConfigs.getPushSegmentProducerConfig().getGroupName());
return producer;
}
可以看到,在这里面是没有调用producer的start()方法的,那么在代码里调用producer.start()方法,会出现如下的报错信息:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rocketMQTemplate' defined in class path resource [org/apache/rocketmq/spring/autoconfigure/RocketMQAutoConfiguration.class]: Invocation of init method failed; nested exception is org.apache.rocketmq.client.exception.MQClientException: The producer service state not OK, maybe started once, RUNNING
See http://rocketmq.apache.org/docs/faq/ for further details.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:847)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1204)
at com.alliance.tca.trigger.Application.main(Application.java:27)
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 com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:64)
Caused by: org.apache.rocketmq.client.exception.MQClientException: The producer service state not OK, maybe started once, RUNNING
See http://rocketmq.apache.org/docs/faq/ for further details.
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.start(DefaultMQProducerImpl.java:214)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.start(DefaultMQProducerImpl.java:175)
at org.apache.rocketmq.client.producer.DefaultMQProducer.start(DefaultMQProducer.java:272)
at org.apache.rocketmq.spring.core.RocketMQTemplate.afterPropertiesSet(RocketMQTemplate.java:861)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
... 21 common frames omitted
报这个错误之前producer的start已经启动成功了,说明除了我们代码调用的start()方法还有地方调用了start()方法。
通过打断点的方式,找到第二次start是在哪调用的,可以看到是RocketMQTemplate的afterPropertiesSet方法调用的,也就是说producer是在RocketMQTemplate生成之后才启动的。
那么问题就很明显了,是producer启动在前,而rocketMQTemplate生成后的启动在后,两次启动造成冲突,因此不能直接用producer调用start()方法。
那么问题就很明显了,是producer启动在前,而rocketMQTemplate生成后的启动在后,两次启动造成冲突,因此不能直接用producer调用start()方法。
同样的上面的分析说到,rocketMQ的producer生成了但是rocketMQTemplate还未初始化,也就是说producer的start()方法没被调用,导致了在使用producer发送消息时导致报错。
那么只需要在使用producer的地方加上rocketMQTemplate的依赖即可
@DependsOn(value = "rocketMQTemplate")
那么另一个问题就是,为什么bean还没加载完,项目还没启动就会调用producer去发送消息?
因为我们发送消息的地方是监听rocketMQ的消息处理完成后再发一条消息到rocketMQ,而rocketMQ consumer的处理在其consumer加载完成后就开始了,并不会等到项目启动后才开始消费。
综上,我们在使用rocketMQ时,如果有在消费消息中使用生产者,需要处理好bean的依赖关系.