領域事件就字面理解爲,領域內已發生的活動,這是一個有具體狀態的事件。工具
將領域中所發生的活動建模成一系列的離散事件。每一個事件都用領域對象來表示。領域事件是領域模型的組成部分,表示領域中所發生的事情。字體
要點:「領域事件是領域模型的組成部分」,經過這句話能夠得知,領域事件不會是領域模型,那麼在具體代碼中領域事件是做爲實體仍是值對象呢?中間件
事件直接的理解是「已經」發生的活動,是不變,因此值對像是比較好的選擇。對象
領域事件是一個領域模型中極其重要的部分,用來表示領域中發生的事件。忽略不相關的領域活動,同時明確領域專家要跟蹤或但願被通知的事情,或與其餘模型對象中的狀態更改相關聯。事件
要點:事務
領域事件做爲領域模型的重要部分,是領域建模的工具之一。it
領域建模即分析業務,而領域事件是領域中一種狀態的反應,例如肚子餓了,會經過神經感受反饋給身體餓了這個信息。而這個信息可讓咱們得知領域會作哪些業務。支付
用來捕獲領域中已經發生的事情。數據
已發生的事情才被稱之爲事件。語言
並非領域中全部發生的事情都要建模爲領域事件,要忽略無業務價值的事件。
例如人的身體不會告訴人自己指甲太長了,可是卻會通知身體肚子餓了,由於指甲長不影響人的存貨,而餓肚子卻會被餓死。即有價值才值得建模事件。
領域事件是領域專家所關心的(須要跟蹤的、但願被通知的、會引發其餘模型對象改變狀態的)發生在領域中的一些事情。
同第三點所述同樣,有價值纔會被關心才能做爲領域事件。
簡而言之,領域事件是用來捕獲領域中發生的具備業務價值的一些事情。它的本質就是事件,不要將其複雜化。在DDD中,領域事件做爲通用語言的一種,是爲了清晰表述領域中產生的事件概念,幫助咱們深刻理解領域模型。
上述中
領域事件是領域專家所關心的(須要跟蹤的、但願被通知的、會引發其餘模型對象改變狀態的)發生在領域中的一些事情。
從這句話能夠知道,領域事件所作的是跟蹤事件和通知,也就是當發生了某件事情,纔去作某一個操做。
例如:
當用戶下單,扣除庫存。
當用戶支付,扣除用戶餘額。
當用戶簽收包裹,訂單狀態變動已簽收。
那麼,這些都是領域事件嗎?回到剛纔的話中,「須要跟蹤的、但願被通知的、會引發其餘模型對象改變狀態的」 用戶下單扣除庫存是即時的操做,不知足加粗字體句中的三個條件。 用戶支付扣除餘額同理。用戶簽收包裹變動訂單狀態,知足會引發其餘模型對象改變狀態這個條件,因此是領域事件。
因此只有須要被跟蹤、被通知、會改變其餘模型狀態的業務,才須要建立領域事件。
接上面簽收例子,當訂單狀態變動後,商家從第三方平臺收到貨款,這個時候領域中是最終一致性的。因此部分領域事件是能夠保持領域最終一致性。
上述多個例子中能夠分析出,不管是變動訂單狀態,仍是商家收到貨款,這些都不是具體業務,既然如此,在使用領域事件時應該是可以保持原代碼不作業務改變的,保證業務不變,只是對業務結果作出處理。
再者應當是能夠解決領域的聚合性問題。DDD中的聚合有一個原則是,在單個事務中,只容許對一個聚合對象進行修改,由此產生的其餘改變必須在單獨的事務中完成。若是一個業務跨多個聚合對象,領域事件會是一個不錯的工具來解決這個問題。經過領域事件的方式能夠達到各個組件之間的數據一致性,經過最終一致性取代事務一致性。
那麼如何建模領域事件呢?
事件存儲,顧名思義,即事件的持久化。那爲何要持久化事件?
簡單來講就是記錄當時的領域狀態。
當事件發佈失敗時,可用於從新發布。
經過消息中間件去分發事件,提升系統的吞吐量。
用於事件溯源。
源代碼管理工具咱們都用過,如Git、SVN等,經過記錄文件每一次的修改記錄,以便咱們跟蹤每一次對源代碼的修改,從而咱們能夠隨時回滾到文件的指定修改版本。
事件溯源的本質亦是如此,不過它存儲的並不是聚合每次變化的結果,而是存儲應用在該聚合上的歷史領域事件。當須要恢復某個狀態時,須要把應用在聚合的領域事件按序「重放」到要恢復狀態對應的領域事件爲止。
通過上面的分析,咱們知道引入領域事件的目的主要有兩個,一是解耦,二是實現數據的最終一致性。
最後,對於領域事件,咱們能夠這樣理解:
經過將領域中所發生的活動建模成一系列的離散事件,跟蹤事件執行相應的業務邏輯。
也能夠簡要理解爲:領域事件 = 事件發佈 + 事件存儲 + 事件分發 + 事件處理。