Spring Event + 非同步實現業務的解耦(結合Spring Retry重試)
theme: channing-cyan
使用場景
- 專案開發中經常會涉及到非常複雜的業務邏輯,如果全部耦合在一起,一個類的程式碼就會非常長,所以需要我們對業務程式碼進行解耦。通常在一個複雜的邏輯業務裡面,會包含一個核心業務和N個子業務,有些子業務,我們是不需要在當前請求中同步完成的,例如簡訊傳送等。這時,我們可能會想到MQ。但是當我們不想引入MQ時,就可以考慮使用Spring Event,它相當於一個觀察者模式,當一個Bean完成任務之後,會通知另一個Bean去執行相應的任務。
- Spring Retry也是Spring裡的一個元件,主要實現是發生異常後重新呼叫。當一些瞬時錯誤(例如網路問題)發生時,Spring Retry的重試可以幫我們避免這種異常造成的服務呼叫失敗的情況。
使用案例
自定義事件
@Data
@AllArgsConstructor
public class MsgEvent {
private String msgId;
}
定義監聽器
```` @Component @Slf4j public class MsgListener {
/**
* value值表示當哪些異常的時候觸發重試,
* maxAttempts表示最大重試次數預設為3,
* delay表示重試的延遲時間,
* multiplier表示上一次延時時間是這一次的倍數。
* @param event
*/
@EventListener
@Async
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
public void sendMsg(MsgEvent event) {
String msgId = event.getMsgId();
StopWatch watch = new StopWatch(msgId);
watch.start();
log.info("開始發簡訊");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
watch.stop();
log.info("簡訊傳送成功, 訊息id:【{}】 | 耗時: ({})", msgId, watch.getLastTaskTimeMillis());
}
} ````
啟動類
新增@EnableAsync和@EnableRetry註解
@SpringBootApplication
@EnableAsync
@EnableRetry
public class LabApplication {
public static void main(String[] args) {
SpringApplication.run(LabApplication.class, args);
}
}
單元測試
``` @SpringBootTest @Slf4j public class EventTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void msgTest() {
applicationContext.publishEvent(new MsgEvent("123"));
log.info("簡訊傳送事件釋出成功");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} ```