用 Spring 思維快速上手 DDD——以 Kratos 為例的分層解讀

用 Spring 思維理解 DDD —— 以 Kratos 為參照

? 在此前的學習工作中,使用的開發框架一直都是 SpringBoot,對 MVC 架構幾乎是肌肉記憶:Controller 接請求,Service 寫業務邏輯,Mapper 操作數據庫,這套套路早已深入骨髓。
? 最近開始學習 Go,為了寫微服務,接觸到了 Kratos 框架,也順帶深入了解了 DDD(領域驅動設計)。一開始,我的第一反應是——“這不就是 MVC 換個說法嗎?”
但越學越發現,雖然 DDD 和我們熟悉的 Spring MVC 分層在形狀上很像,但它對“業務邏輯該放哪、數據訪問該放哪”劃分得更嚴格,還用工程化的方式強制執行這些規則。
? 這篇文章,我就用自己熟悉的 Java Spring 思維,把 DDD 的分層思想翻譯成 Spring 語言,再對照 Kratos 在 Go 里的實現,幫你快速搞懂它們的異同。

在這里插入圖片描述

往期博客

Go語言新手村:輕松理解變量、常量和枚舉用法
Go 語言中的結構體、切片與映射:構建高效數據模型的基石

1. Spring 的常見分層

在 Java 項目中,最典型的分層是:

Controller → Service → Mapper → DB
  • Controller:接收請求、參數校驗、調用 Service
  • Service:執行業務邏輯(有時混合數據訪問)
  • Mapper:訪問數據庫(MyBatis Mapper / JPA Repository)

這種分層沒錯,而且配合團隊自律,也能寫出很干凈的項目結構。但現實是:

  • Service 往往既寫業務規則,又寫 SQL 條件拼接;
  • 業務規則分散在 Service、Mapper 甚至 Controller 中;
  • 一旦底層數據訪問方式變化(換數據庫、換 RPC),改動會影響大量上層代碼。

2. DDD 的目標:邊界清晰、職責單一

DDD 要解決的,就是讓業務邏輯與技術實現徹底解耦,做到:

  • 業務規則集中在領域模型中,貼著數據維護不變式;
  • 數據訪問細節被隔離在倉儲實現中,隨時可替換;
  • 跨聚合的編排邏輯集中在應用服務(Usecase)中,清晰可測。

DDD 的典型分層

接口層(Controller / API)→ 應用層(Usecase / Application Service)→ 領域層(Entity / Aggregate / Domain Service / Repository 接口)→ 基礎設施層(Repository 實現 / 外部服務實現)

3. 用 Spring 語言對照 DDD 分層

DDD 層次Kratos 對應Spring 對應職責
接口層(API)serviceController參數校驗、鑒權、DTO ? Domain 轉換
應用層(Usecase)bizService(理想狀態)編排業務流程、事務控制、調用多個領域對象或外部服務
領域層repo實體類、領域服務接口維護業務不變式、暴露行為方法、定義倉儲接口
基礎設施層dataMapper / Feign 實現層數據持久化、調用遠程服務、模型映射(PO ? Domain)

4. 核心理念對比

4.1 Repository

  • Spring 常見寫法:Mapper/Repository 接口直接返回 PO(數據庫模型),業務層可能直接用它判斷。
  • DDD 寫法:倉儲接口定義在領域層,返回的是領域對象(封裝了業務行為的方法),由基礎設施層實現。

4.2 業務規則的位置

  • 常見誤區:在 Service 里寫 if (user.getEnabled() == 0) throw ...
  • DDD 方式:在領域對象中提供 ensureActive(),領域對象自己決定什么是可用

4.3 應用服務(Usecase)

  • 職責:一次完整業務流程的編排、事務邊界、調用多個倉儲接口、發布領域事件。
  • 不做的事:不直接寫 SQL,不去判斷 user.getEnabled(),不實現底層細節。

5. 案例:鎖單流程

下面的鎖單方法只是為了演示 DDD 分層思路,并不具備生產可用性。在真實系統中,鎖單流程往往要面對并發控制一致性等復雜問題。

5.1 常見 Spring 寫法(簡化版)

@Service
@AllArgsConstructor
public class OrderService {private final OrderMapper orderMapper;private final UserMapper userMapper;private final StockMapper stockMapper;private final WalletMapper walletMapper;@Transactionalpublic String lockOrder(String userId, String sku, int count) {// 校驗賬戶是否可用if (!userMapper.ensureActive(userId)) {throw new BizException("用戶不可用");}// 校驗庫存if (!stockMapper.hasStock(sku, count)){throw new BizException("商品庫存不足");}// 檢查余額if (!walletMapper.hasBalance(userId, count * price)){ throw new BizException("余額不足");}// 預減庫存stockMapper.reserveStock(...);// 凍結余額walletMapper.freezeBalance(...);// 添加一條訂單記錄orderMapper.insertOrder(...);return orderId;}
}

缺點:業務判斷和數據訪問混雜

5.2 DDD 寫法(Spring 風格)

領域層(實體類 + 倉儲接口)
// 聚合根:用戶
public class User {public void ensureActive() { /* 校驗用戶有效性 */ }
}// 聚合根:庫存
public class Stock {public void reserve(int count) { /* 校驗庫存并預留 */ }
}// 聚合根:錢包
public class Wallet {public void freeze(double amount) { /* 校驗余額并凍結 */ }
}// 倉儲接口
public interface UserRepo { User load(String id); void save(User u); }
public interface StockRepo { Stock load(String sku); void save(Stock s); }
public interface WalletRepo { Wallet load(String uid); void save(Wallet w); }
public interface OrderRepo { void save(Order o); }
應用層(用例編排)
@Service
@AllArgsConstructor
public class LockOrderUsecase {private final UserRepo userRepo;private final StockRepo stockRepo;private final WalletRepo walletRepo;private final OrderRepo orderRepo;public void lock(String userId, String sku, int qty, double price) {// 調用倉儲接口,獲取領域對象User user = userRepo.load(userId);Stock stock = stockRepo.load(sku);Wallet wallet = walletRepo.load(userId);// 業務編排user.ensureActive();stock.reserve(qty);wallet.freeze(qty * price);// 持久化數據orderRepo.save(new Order());stockRepo.save(stock);walletRepo.save(wallet);}
}
  • 業務邏輯在領域對象:例如ensureActivereservefreeze方法,他們只關心業務實現,不關心數據是怎么獲取的
  • 數據訪問集中在倉儲實現:Repo 不做業務判斷,取出來交給實體自己判斷
  • 應用層清晰編排流程:用 Repo 加載實體 → 調用實體方法做判斷/修改 → 再通過 Repo 保存變更

6. Kratos 如何落地

Kratos 在 Go 里用目錄結構 + wire 靜態注入強制執行這種依賴方向:

service(接口層) → biz(用例+倉儲接口) → data(倉儲實現) → DB/遠程服務
  • biz 中不能 import ORM/HTTP 客戶端等具體庫;
  • data 中實現所有倉儲接口,負責 PO ? Domain 映射;
  • service 只負責接收請求、調用 Usecase。

這跟 Spring 在理想狀態下的分層幾乎一致,但 Kratos 用工程手段物理防止越層,減少團隊自律成本。

7. 總結

用 Spring 開發者的眼光看:

  • DDD 并不是要你放棄 Controller/Service/Mapper,而是讓 Service 變成 應用服務,專注業務編排;
  • 業務判斷應該寫在領域對象中,不應該在 Mapper 或 Service 里直接寫;
  • Repository 接口定義在領域層,實現放在基礎設施層;

領域模型對外暴露的是業務語義,數據訪問實現細節被封裝在倉儲里,上層業務不感知底層變化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92869.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92869.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92869.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

docspace|Linux|使用docker完全離線化部署onlyoffice之docspace文檔協作系統(全網首發)

一、 前言 書接上回,Linux|實用工具|onlyoffice workspace使用docker快速部署(離線和定制化部署)-CSDN博客,如果是小公司或者比如某個項目組內部使用,那么,使用docspace這個文檔協同系統是非常合適的&…

【教程】如何高效提取胡蘿卜塊根形態和顏色特征?

胡蘿卜是全球不可或缺的健康食材和重要的經濟作物, 從田間到餐桌,從鮮食到深加工,胡蘿卜在現代人的飲食和健康中扮演著極其重要的角色,通過量化塊根形態和色澤均勻性,可實現對高產優質胡蘿卜品種的快速篩選。工具/材料…

Python初學者筆記第二十四期 -- (面向對象編程)

第33節課 面向對象編程 1. 面向對象編程基礎 1.1 什么是面向對象編程面向過程:執行者 耗時 費力 結果也不一定完美 面向對象:指揮者 省時 省力 結果比較完美面向對象編程(Object-Oriented Programming, OOP)是一種編程范式,它使用"對象&…

Go 語言 里 `var`、`make`、`new`、`:=` 的區別

把 Go 語言 里 var、make、new、: 的區別徹底梳理一下。1?? var 作用:聲明變量(可以帶初始值,也可以不帶)。語法: var a int // 聲明整型變量,默認值為 0 var b string // 默認值 ""…

計算機網絡---IP(互聯網協議)

一、IP協議概述 互聯網協議(Internet Protocol,IP)是TCP/IP協議族的核心成員,位于OSI模型的網絡層(第三層),負責將數據包從源主機傳輸到目標主機。它是一種無連接、不可靠的協議,提供…

DataFun聯合開源AllData社區和開源Gravitino社區將在8月9日相聚數據治理峰會論壇

🔥🔥 AllData大數據產品是可定義數據中臺,以數據平臺為底座,以數據中臺為橋梁,以機器學習平臺為中層框架,以大模型應用為上游產品,提供全鏈路數字化解決方案。 ?杭州奧零數據科技官網&#xff…

【工具】通用文檔轉換器 推薦 Markdown 轉為 Word 或者 Pdf格式 可以批量或者通過代碼調用

【工具】通用文檔轉換器 推薦 可以批量或者通過代碼調用 通用文檔轉換器 https://github.com/jgm/pandoc/ Pandoc - index 下載地址 https://github.com/jgm/pandoc/releases 使用方法: 比如 Markdown 轉為 Word 或者 Pdf格式 pandoc -s MANUAL.txt -o example29.docx …

【UEFI系列】Super IO

文章目錄一、什么是Super IO二、Super IO的作用常見廠商三、邏輯設備控制如何訪問SIO邏輯設備的配置寄存器具體配置數值四、硬件監控(hardware monitor)一、什么是Super IO Super Input/Output超級輸入輸出控制器。 通過LPC(low pin count&a…

飛算 JavaAI 2.0.0 測評:自然語言編程如何顛覆傳統開發?

一、前言 在AI技術高速發展的今天,編程方式正在經歷一場革命。傳統的“手寫代碼”模式逐漸被AI輔助開發取代,而飛算JavaAI 2.0.0的推出,更是讓自然語言編程成為現實。 作為一名長期使用Java開發的程序員,我決定深度體驗飛算Java…

Dubbo + zk 微服務

一、安裝zk注冊中心 win版本:windows環境下安裝zookeeper教程詳解(單機版)-CSDN博客 linux版本: 二、服務提供方搭建 引入dubbo和zk依賴 提供接口 使用注解方式實現接口級注冊到zk,而springcloud是將服務注冊到注冊…

聆思duomotai_ap sdk適配dooiRobot

一、說明 1、duomotai_ap介紹 duomotai_ap是一個針對多模態開發板(如 CSK6-MIX 開發板)的大模型 AI 開發套件 SDK,主要用于開發語音、視覺等多模態 AI 應用。 2、dooiRobot介紹 基于Doly 機器人的經典外觀設計,采用聆思CSK6011A…

Photoshop軟件打開WebP文件格的操作教程

Photoshop軟件打開WebP文件格的操作教程,好吧,這是英文原版: Photoshop 23.2 原生支持 WebP 格式,無需插件即可打開、編輯和保存 WebP 文件。用戶可通過“文件 > 另存為副本”選擇 WebP 格式,調整無損/有損壓縮及質…

【數據結構】——順序表鏈表(超詳細解析!!!)

目錄一. 前言二. 順序表1. 順序表的特點2. 代碼實現三. 鏈表1. 單向鏈表代碼實現2.雙向鏈表代碼實現四. 順序表與鏈表的區別總結一. 前言 順序表和鏈表是最基礎的兩種線性表實現方式。它們各有特點,適用于不同的應用場景。本文將詳細介紹這兩種數據結構的實現原理、…

GitHub的簡單使用方法----(4)

在安裝完git之后,桌面右鍵會出現兩個git的選項第一個gui打開是這樣的用戶界面分別是新建倉庫,克隆倉庫,打開已經存在的倉庫。tips:Git Gui 默認只能操作本地倉庫——它本質上是一個圖形化的“本地 Git 客戶端”。 它本身不內置“下載遠程倉庫…

藍橋杯----大模板

在寫大模板之前,先講一個函System_Init(),用于系統初始化關閉所有LED與外設,關閉所有LED就是傳入0xff數據打開鎖存器,關閉外設就是傳入0x00打開鎖存器。現在所有底層已經提供給大家了,先提供最簡單版本的大模板&#x…

科技寫作改革我見:取消參考文獻,以點讀率取代引證率!

科技寫作改革我見:綜述應取消參考文獻,學術成就評估以點讀下載率取代參考文獻引證率!李升偉 張君飛 韓若蘭引言在當今信息爆炸的時代,科技寫作作為知識傳播的核心載體,其形式與評價體系正面臨前所未有的挑戰。傳統…

【Altium designer】快速建立原理圖工程的步驟

快速建立原理圖工程的步驟產品規格書分析 整理產品需求,明確主控芯片、外圍接口類型、總線頻率、電源需求及隔離要求、PCB尺寸等關鍵信息。使用文本清單列出所有需求,確保無遺漏。硬件需求架構圖繪制 根據需求說明書和收集的信息,使用VISIO繪…

Origin2025b安裝包免費,附Origin 2025安裝教程

老規矩先放鏈接:origin2025b安裝包 有位小粉絲問我有沒有Origin2025b的安裝包,有的兄弟有的,只有你想不到,沒有小兔找不到的軟件。 這個origin是OriginLab公司開發的一個科學繪圖、數據分析的軟件,Origin支持各種各樣…

【C++語法】輸出的設置 iomanip 與 std::ios 中的流操縱符

文章目錄【C語法】輸出的設置 iomanip 與 std::ios 中的流操縱符1. iomanip 中的流操縱方法1.1 位寬操作類1.1.1 std::setw(x)1.1.2 std::setfill(c)1.1.3 std::left1.1.4 std::right1.1.5 std::internal1.2 小數操作類1.2.1 std::fixed1.2.2 std::setprecision(x)1.2.3 std::s…

go語言學習筆記-Map

map 是一種無序的基于 key-value 的數據結構,Go 語言中的 map 是引用類型,必須初始化 才能使用。 Go 語言中 map 的定義語法如下map[KeyType]ValueType常見兩種創建方法1 使用map初始化var scoreMap make(map[string]int, 8) scoreMap["陳翔"…