在Spring里我們可以使用Spring Cloud AWS里的SqsListener方便地在后臺(tái)持續(xù)接收SQS消息。官方文檔給出的樣例如下:
@SqsListener("queueName")
public void queueListener(Person person) {
// ...
}
如果消費(fèi)消息的過(guò)程中出現(xiàn)exception
怎么辦呢搁胆?這點(diǎn)文檔中并沒(méi)有講解。最簡(jiǎn)單的異常處理织盼,顯而易見(jiàn)砰粹,就是直接在消息處理中使用try-catch
:
@SqsListener("queueName")
public void queueListener(Person person) {
try {
// ...
} catch (Exception e) {
// exception handling
}
}
但是(凡事就怕“但是”),queueListener
中不再拋出任何exception
會(huì)導(dǎo)致Spring認(rèn)為這條消息消費(fèi)成功了许起,于是依據(jù)@SqsListener
的deletionPolicy
屬性笋熬,Spring有可能向SQS請(qǐng)求刪除這條消息热某。那么如何更優(yōu)雅地處理SQS消息消費(fèi)中出現(xiàn)的exception
呢?
我們知道胳螟,Spring常用separation of concerns原則來(lái)分解問(wèn)題昔馋,所以我猜我們可以用某種方式向Spring注冊(cè)一個(gè)處理異常方法。細(xì)心查閱SqsListener的文檔糖耸,我們可以發(fā)現(xiàn)Spring在實(shí)現(xiàn)時(shí)使用了@MessageMapping這個(gè)來(lái)自spring-messaging的注解秘遏。從這個(gè)注解出發(fā)去繼續(xù)查找文檔,不難找到嘉竟,spring-messaging會(huì)掃描@MessageExceptionHandler來(lái)發(fā)現(xiàn)自定義的異常處理方法邦危。于是,我們?cè)?code>@SqsListener所修飾的方法的同一類(lèi)中同時(shí)加入用@MessageExceptionHandler
修飾的方法便可以捕捉消息消費(fèi)時(shí)產(chǎn)生的異常舍扰,同時(shí)又不影響Spring對(duì)消息消費(fèi)成功與否的判定:
public class SqsConsumer {
@SqsListener("queueName")
public void queueListener(Persone person) {
// ...
}
@MessageExceptionHandler
public void exceptionHandler(Exception e) {
// exception handling
}
}
Spring支持在調(diào)用異常處理方法時(shí)注入消息的payload
和headers
等信息幫助我們記錄和處理倦蚪。如果我們想更細(xì)致地控制SQS消息生命周期,Spring也支持注入Acknowledgment
來(lái)刪除消息或Visibility
來(lái)更新消息的timeout
边苹。
@MessageExceptionHandler
public void exceptionHandler(
Exception e,
// 以String注入payload审丘,或`T message`,Spring會(huì)使用`MessageConverter`將消息轉(zhuǎn)換為T(mén)類(lèi)型
String payload,
// 注入全部headers勾给,或用`@Header("MessageId") String messageId`注入具體某一條header
MessageHeaders headers,
Acknowledgment acknowledgment,
Visibility visibilityHandler
) {
// exception handling
}