掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
領(lǐng)域事件是 DDD 中重要的模式之一,主要用于模型或系統(tǒng)間的解耦,提高系統(tǒng)的可擴展性和可維護性。
領(lǐng)域事件是領(lǐng)域驅(qū)動設(shè)計(Domain-Driven Design,簡稱DDD)中的一個重要概念,特指在領(lǐng)域模型中發(fā)生的有意義的事件,是對領(lǐng)域模型中的重要業(yè)務動作執(zhí)行結(jié)果的抽象,如訂單創(chuàng)建、支付完成等。
在DDD中,領(lǐng)域事件是一種用于傳遞信息的機制,它使得不同領(lǐng)域模型之間的通信變得更加簡單和靈活。通過將事件分發(fā)給相關(guān)的訂閱者,可以讓不同的領(lǐng)域模型之間實現(xiàn)松耦合,從而更容易擴展和維護應用程序。
領(lǐng)域事件通常由領(lǐng)域?qū)ο笾鲃佑|發(fā)并發(fā)布,而事件處理器則負責訂閱事件并對事件進行處理。通過事件發(fā)布和訂閱機制,可以在應用程序中實現(xiàn)高效的事件驅(qū)動架構(gòu),從而更好地支持復雜的業(yè)務邏輯和業(yè)務流程。
說起來有點抽象,簡單舉個例子:
假設(shè)有一個電子商務系統(tǒng),用戶下單后需要生成訂單并發(fā)送通知給相關(guān)人員。在領(lǐng)域模型中,可以定義一個 Order 領(lǐng)域?qū)ο螅搶ο罂梢园鄠€屬性,如訂單號、下單時間、購買的商品信息、收貨地址等等。當用戶下單時,可以通過調(diào)用 Order 對象的方法來生成訂單,同時也可以通過領(lǐng)域事件來發(fā)送通知。
具體來說,可以定義一個 OrderCreated 領(lǐng)域事件,用于表示訂單創(chuàng)建完成的事件,該事件包含一些必要的屬性,如訂單號、下單時間、購買的商品信息、收貨地址等等。當 Order 對象創(chuàng)建完成后,可以通過領(lǐng)域事件來觸發(fā)發(fā)送通知的操作,比如發(fā)送郵件或短信通知相關(guān)人員。
領(lǐng)域事件的應用創(chuàng)建眾多,從圖中可以看出:
領(lǐng)域事件可以:
領(lǐng)域事件雖好,但仍需技術(shù)框架進行支持,其實 Spring 的 Event 機制就足以滿足各類需求。
在 Spring 中,事件的處理可以通過三種方式來實現(xiàn):
由于與 Spring 存在強耦合,現(xiàn)在已經(jīng)很少使用,可以直接跳過。
下面是一個基于接口的事件處理的示例代碼:
@Component
public class MyEventListener implements ApplicationListener{
@Override
public void onApplicationEvent(MyEvent event) {
// 處理事件
System.out.println("Received event: " + event.getMessage());
}
}
public class MyEvent {
private String message;
public MyEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
@Component
public class MyEventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishEvent(String message) {
MyEvent event = new MyEvent(message);
eventPublisher.publishEvent(event);
}
}
在這個示例中,MyEvent 是一個自定義的事件類,MyEventListener 是一個實現(xiàn)了 ApplicationListener 接口的監(jiān)聽器,用于處理 MyEvent 事件,MyEventPublisher 是用于發(fā)布事件的類。
當應用程序調(diào)用 MyEventPublisher 的 publishEvent 方法時,會觸發(fā)一個 MyEvent 事件,MyEventListener 中的 onApplicationEvent 方法將被自動調(diào)用,從而處理這個事件。
Spring 提供 @EventListener 和 @TransactionListener 兩個注解以簡化對事件的處理。
Spring 的 EventListener 監(jiān)聽器是一種相對于傳統(tǒng)的事件監(jiān)聽方式更為簡潔和靈活的事件機制。與傳統(tǒng)的事件機制不同,EventListener 不需要顯示地繼承特定的事件接口,而是使用注解標識需要監(jiān)聽的事件類型,然后通過一個單獨的監(jiān)聽器類處理所有類型的事件。
相比之下 EventListener 的優(yōu)勢主要有以下幾點:
以下是一個簡單的例子:
@Component
public class MyEventListener{
@EventListener
public void onApplicationEvent(MyEvent event) {
// 處理事件
System.out.println("Received event: " + event.getMessage());
}
}
public class MyEvent {
private String message;
public MyEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
@Component
public class MyEventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishEvent(String message) {
MyEvent event = new MyEvent(message);
eventPublisher.publishEvent(event);
}
}
相比基于接口的事件處理,EventListener 是一種更加簡潔、靈活、松耦合、可測試的事件機制,能夠有效地降低開發(fā)的復雜度,提高開發(fā)效率。
在 Spring 中,TransactionEventListner 和 EventListner 都是用于處理事件的接口。不同之處在于
具體來說,在使用 Spring 的聲明式事務時,可以在事務提交后觸發(fā)某些事件。這就是 TransactionEventListner 的應用場景。而 EventListner 則不涉及事務,可以用于在事件發(fā)布后觸發(fā)一些操作。
下面是一個簡單的示例,演示了如何使用 TransactionEventListner 和 EventListner:
@Component
public class MyEventListener {
@EventListener
public void handleMyEvent(MyEvent event) {
// 處理 MyEvent
}
@TransactionalEventListener
public void handleMyTransactionalEvent(MyTransactionalEvent event) {
// 處理 MyTransactionalEvent
}
}
@Service
public class MyService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private MyRepository myRepository;
@Transactional
public void doSomething() {
// 做一些事情
MyEntity entity = myRepository.findById(1L);
// 發(fā)布事件
eventPublisher.publishEvent(new MyEvent(this, entity));
// 發(fā)布事務事件
eventPublisher.publishEvent(new MyTransactionalEvent(this, entity));
}
}
在這個例子中,MyEventListener 類定義了兩個方法,handleMyEvent 和
handleMyTransactionalEvent,分別處理 MyEvent 和 MyTransactionalEvent 事件。其中,handleMyTransactionalEvent 方法用 @TransactionalEventListener 注解標記,表示它只會在事務提交后觸發(fā)。
MyService 類中的 doSomething 方法使用 ApplicationEventPublisher 來發(fā)布事件。注意,它發(fā)布了兩種不同類型的事件:MyEvent 和 MyTransactionalEvent。這兩個事件會分別觸發(fā) MyEventListener 中的對應方法。
總的來說,Spring 的事件機制非常靈活,可以方便地擴展應用程序的功能。TransactionEventListner 和 EventListner 這兩個接口的應用場景有所不同,可以根據(jù)實際需求選擇使用。
@Async是Spring框架中的一個注解,用于將一個方法標記為異步執(zhí)行。使用該注解,Spring將自動為該方法創(chuàng)建一個新線程,使其在后臺異步執(zhí)行,不會阻塞主線程的執(zhí)行。
在具體應用中,使用@Async可以大大提升應用的并發(fā)處理能力,使得系統(tǒng)能夠更快地響應用戶請求,提高系統(tǒng)的吞吐量。
@Async 和 @EventListener 或 @TransactionEventListener 注解在一起使用時,會產(chǎn)生異步的事件處理器。使用這種組合的方式,事件處理器會在單獨的線程池中執(zhí)行,以避免阻塞主線程。這種方式在需要處理大量事件或者事件處理器耗時較長的情況下非常有用,可以有效提高應用的性能和可伸縮性。同時,Spring 框架對這種方式也提供了完善的支持,可以方便地使用這種方式來實現(xiàn)異步事件處理。
下面是一個簡單的示例代碼,演示了如何在 Spring 中使用 @Async 和 @EventListener 一起實現(xiàn)異步事件處理:
@Component
public class ExampleEventListener {
@Async
@EventListener
public void handleExampleEvent(ExampleEvent event) {
// 在新的線程中執(zhí)行異步邏輯
// ...
}
}
在這個示例中,ExampleEventListener 類中的 handleExampleEvent 方法使用了 @Async 和 @EventListener 注解,表示這個方法是一個異步事件監(jiān)聽器。當一個 ExampleEvent 事件被觸發(fā)時,這個方法會被異步地執(zhí)行。在這個方法中,可以執(zhí)行任何異步的邏輯處理,比如向隊列發(fā)送消息、調(diào)用其他服務等。
備注:在使用 @Async 時,需要根據(jù)業(yè)務場景對線程池進行自定義,以免出現(xiàn)資源不夠的情況(Spring 默認使用單線程處理@Async異步任務)
綜上所述,當領(lǐng)域事件發(fā)出來之后,不同的注解會產(chǎn)生不同的行為,簡單匯總?cè)缦拢?/p>
|
@EventListener |
@TransactionEventListener | |
|
無 @Async |
順序、同步執(zhí)行 |
事務提交后、同步執(zhí)行 |
|
有 @Async |
順序、異步執(zhí)行 |
事務提交后、異步執(zhí)行 |
特點:
應用場景:
特點:
應用場景:
備注:
@TransactionEventLisnter 必須在事務上下文中,脫離上下文,調(diào)用不會生效
特點:
應用場景:
特點:
應用場景:
異步處理。記錄操作日志,異步保存數(shù)據(jù)等
備注:
@TransactionEventLisnter 必須在事務上下文中,脫離上下文,調(diào)用不會生效
領(lǐng)域事件的落地,不僅需要強大的設(shè)計能力,還需要與之匹配的基礎(chǔ)設(shè)施。Spring 作為最常用的框架,基于發(fā)布訂閱實現(xiàn)了完整的一套 Event 管理機制。工具在手是否能根據(jù)業(yè)務場景選擇合適的解決方案就成了研發(fā)的職責,簡單思考以下組合適用場景是什么:

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流