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被徹底卸載之前
總結
在解決問題這種加載順序問題時,多多研究項目需求,優化方案,關鍵時刻需要去查看源碼,詳細了解底層的加載順序,各個注解的使用也是非常重要的,有時候一個注解可以抵上自己的好幾百行垃圾代碼。哈哈哈~~~~