RabbitMq消费者在初始配置之后进行数据消费
RabbitMq消费者在初始配置之后进行数据消费
问题背景
在写一个消费rabbitmq消息的程序是,发现了一个问题,消费者的业务逻辑里面依赖这一些配置信息,但是当项目启动时,如果队列里面有积压数据的时候,就会出现配置信息还没有加载完成就开始进行数据消费了,这样就会出现业务逻辑混乱的情况,所以现在想要做的就是在项目启动时,等待项目的一些配置信息加载完成之后,再进行消息消费的逻辑。
解决方案
方案一
定义一个全局标示变量(用来表示配置加载是否完成),在消费者的消费逻辑开始时判断配置是否加载完成。代码如下:
/**
* 消费者方法
*/
public void messageHandle(Channel channel, Message message) {
handleMessage(channel, message);
}
private void handleMessage(Channel channel, Message message) {
// 如果有需要在消费前加载的数据库缓存信息可以使用以下注释方法进行等待初始化结束后再进行后续操作
// Constants.InitFlag 就是全局的线程安全变量
// public static AtomicBoolean InitFlag = new AtomicBoolean(false);
while (!Constants.InitFlag.get()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("项目正在初始化 ~~~ ");
}
// 手动 ack
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
/**
* 配置加载初始化方法
*/
public void initConfig(){
// 具体的加载配置业务逻辑,这里就用睡眠代替了
Thread.sleep(10000);
// 加载完成之后,将变量置为 true
InitFlag.getAndSet(true);
}
方案二
研究了下spring各个注解启动的顺序之后,使用 @PostConstruct 其实可以更简单的实现这种需求,方案一是没有考虑到spring的加载顺序写出来的,所以不是很完美,但是可以解决需求。
@Component
@Slf4j
public class InitConfig {
// @Autowired 可以注入一些业务逻辑对象,进行操作
@PostConstruct
public void run() throws InterruptedException {
// messageProduce.sendMessage();
log.info("初始化开始");
Thread.sleep(Long.parseLong("10000"));
log.info("初始化完成");
}
}
这样的话,消费者就会在这些初始化业务完成之后才会进行消费。
备注
@PostConstruct
用来标记是在项目启动的时候执行这个方法。用来修饰一个非静态的void()方法
也就是spring容器启动时就执行,多用于一些全局配置、数据字典之类的加载
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
@PreDestroy
被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前
总结
在解决问题这种加载顺序问题时,多多研究项目需求,优化方案,关键时刻需要去查看源码,详细了解底层的加载顺序,各个注解的使用也是非常重要的,有时候一个注解可以抵上自己的好几百行垃圾代码。哈哈哈~~~~