Listener method 'public void com.config.mq.MsgReceiver.process(java.lang.String) throw
RabbitMQ监听消息时遇到的错误,项目启动就会持续跳出来,其实仔细可以明白其意思,就是有一个公有化的监听方法参数是String类型,所以抛出异常;
开始的时候这样是不会报错的,因为RabbitMQ中队列接受的就是String类型,如果中途因为某种原因,修改了参数的类型,这时参数的类型应该是Message类型,再次切换回String类型或其他类型,就会导致参数类型不匹配,消息无法消费,这是消息的类型会一直保持Message类型,它的类型是向下兼容改变方式;
- 解决这样的问题我有两种方式:
- 简单粗暴,直接打开RabbitMQ服务,找到对应的坐标(交换机、路由器、队列)直接删除,让其重新生成;
- 使用Message(org.springframework.amqp.core.Message),getBody()将参数取出转换成所需要的类型即可;
经过线上多次测试,由于消息生成者和消费者已经配置好了,短时间内上面的两种方式可以解决问题,长时间后还是会出现消费不掉的消息,最后解决采用以下方式:
- 开启线程,参数类型继续为String类型
线程池配置(SpringBoot)
package com.config.async;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置 by CHENYB date 2019-07-29
*/
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Bean
@Override
public Executor getAsyncExecutor() {
//线程池设置
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize( 8 );//核心线程
taskExecutor.setMaxPoolSize( 16 );//最大线程
taskExecutor.setQueueCapacity( 64 );//队列大小
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.setThreadNamePrefix( "async-token-" );
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SpringAsyncExceptionHandler();
}
class SpringAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
//logger.error("Exception occurs in async method", throwable.getMessage());
}
}
}
消费者配置:
其中@Component注解,一定不可以是@Service,会导致消息一旦监听失败,不会重复发起请求,会报错线程问题
在SpringBoot中@Async开启异步
package com.config.mq;
import com.exception.ExceptionEnum;
import com.exception.MyException;
import com.jwt.service.JwtService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* RabbitMQ监听者 by CHENYB of date 2019-07-22
*/
@Component
public class MsgReceiver {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private JwtService jwtService;
/**
* 异步处理&MQ监听整合
* @param message
*/
@RabbitListener(queues = MQCoordinate.TOKENTIMEOUT_QUEUE_A)
@Async
public void process(String message) {
if (StringUtils.isNotBlank( message )){
String userId = message;
logger.info("Token时效队列 监听1(String) {} 中消息: {}",MQCoordinate.TOKENTIMEOUT_QUEUE_A,userId);
if (!this.jwtService.tokenValid( userId ))//更新Token时效
throw new MyException( ExceptionEnum.EXCEPTION_ANALYSIS_TOKEN );
}
}
}
当初就是用的@Service注解,导致线程报错产生,后想去掉线程回归原始,接受消息时采用Message类型,最后标题错误出现,解决本次问题采用的最后的解决方案,即开启了异步消费消息,又解决了消费参数类型不匹配问题,还是有点懵,但是问题解决了
chenyb 随笔记录,只为方便自己学习
2019-10-24