淺談Java開發架構之領域驅動設計DDD落地
一、前言
整個過程大概是這樣的,開發團隊和領域專傢一起通過 通用語言(Ubiquitous Language)去理解和消化領域知識,從領域知識中提取和劃分為一個一個的子領域(核心子域,通用子域,支撐子域),並在子領域上建立模型,再重復以上步驟,這樣周而復始,構建出一套符合當前領域的模型。
二、開發目標
依靠領域驅動設計的設計思想,通過事件風暴建立領域模型,合理劃分領域邏輯和物理邊界,建立領域對象及服務矩陣和服務架構圖,定義符合DDD分層架構思想的代碼結構模型,保證業務模型與代碼模型的一致性。通過上述設計思想、方法和過程,指導團隊按照DDD設計思想完成微服務設計和開發。
1、拒絕泥球小單體、拒絕污染功能與服務、拒絕一加功能排期一個月
2、架構出高可用極易符合互聯網高速迭代的應用服務
3、物料化、組裝化、可編排的服務,提高人效
三、服務架構
3.1、應用層{application}
- 應用服務位於應用層。用來表述應用和用戶行為,負責服務的組合、編排和轉發,負責處理業務用例的執行順序以及結果的拼裝。
- 應用層的服務包括應用服務和領域事件相關服務。
- 應用服務可對微服務內的領域服務以及微服務外的應用服務進行組合和編排,或者對基礎層如文件、緩存等數據直接操作形成應用服務,對外提供粗粒度的服務。
- 領域事件服務包括兩類:領域事件的發佈和訂閱。通過事件總線和消息隊列實現異步數據傳輸,實現微服務之間的解耦。
3.2、領域層{domain}
- 領域服務位於領域層,為完成領域中跨實體或值對象的操作轉換而封裝的服務,領域服務以與實體和值對象相同的方式參與實施過程。
- 領域服務對同一個實體的一個或多個方法進行組合和封裝,或對多個不同實體的操作進行組合或編排,對外暴露成領域服務。領域服務封裝瞭核心的業務邏輯。實體自身的行為在實體類內部實現,向上封裝成領域服務暴露。
- 為隱藏領域層的業務邏輯實現,所有領域方法和服務等均須通過領域服務對外暴露。
- 為實現微服務內聚合之間的解耦,原則上禁止跨聚合的領域服務調用和跨聚合的數據相互關聯。
3.3、基礎層{infrastructrue}
- 基礎服務位於基礎層。為各層提供資源服務(如數據庫、緩存等),實現各層的解耦,降低外部資源變化對業務邏輯的影響。
- 基礎服務主要為倉儲服務,通過依賴反轉的方式為各層提供基礎資源服務,領域服務和應用服務調用倉儲服務接口,利用倉儲實現持久化數據對象或直接訪問基礎資源。
3.4、接口層{interfaces}
接口服務位於用戶接口層,用於處理用戶發送的Restful請求和解析用戶輸入的配置文件等,並將信息傳遞給應用層。
四、開發環境
jdk1.8【jdk1.7以下隻能部分支持netty】
springboot 2.0.6.RELEASE
idea + maven
五、代碼示例
itstack-demo-ddd-01
└── src
├── main
│ ├── java
│ │ └── org.itstack.demo
│ │ ├── application
│ │ │ ├── event
│ │ │ │ └── ApplicationRunner.java
│ │ │ └── service
│ │ │ └── UserService.java
│ │ ├── domain
│ │ │ ├── model
│ │ │ │ ├── aggregates
│ │ │ │ │ └── UserRichInfo.java
│ │ │ │ └── vo
│ │ │ │ ├── UserInfo.java
│ │ │ │ └── UserSchool.java
│ │ │ ├── repository
│ │ │ │ └── IuserRepository.java
│ │ │ └── service
│ │ │ └── UserServiceImpl.java
│ │ ├── infrastructure
│ │ │ ├── dao
│ │ │ │ ├── impl
│ │ │ │ │ └── UserDaoImpl.java
│ │ │ │ └── UserDao.java
│ │ │ ├── po
│ │ │ │ └── UserEntity.java
│ │ │ ├── repository
│ │ │ │ ├── mysql
│ │ │ │ │ └── UserMysqlRepository.java
│ │ │ │ ├── redis
│ │ │ │ │ └── UserRedisRepository.java
│ │ │ │ └── UserRepository.java
│ │ │ └── util
│ │ │ └── RdisUtil.java
│ │ ├── interfaces
│ │ │ ├── dto
│ │ │ │ └── UserInfoDto.java
│ │ │ └── facade
│ │ │ └── DDDController.java
│ │ └── DDDApplication.java
│ ├── resources
│ │ └── application.yml
│ └── webapp
│ └── WEB-INF
│ └── index.jsp
└── test
└── java
└── org.itstack.demo.test
└── ApiTest.java
application/UserService.java | 應用層用戶服務,領域層服務做具體實現
public interface UserService { UserRichInfo queryUserInfoById(Long id); }
domain/repository/IuserRepository.java | 領域層資源庫,由基礎層實現
public interface IUserRepository { void save(UserEntity userEntity); UserEntity query(Long id); }
domain/service/UserServiceImpl.java | 應用層實現類,應用層是很薄的一層可以隻做服務編排
@Service("userService") public class UserServiceImpl implements UserService { @Resource(name = "userRepository") private IUserRepository userRepository; @Override public UserRichInfo queryUserInfoById(Long id) { // 查詢資源庫 UserEntity userEntity = userRepository.query(id); UserInfo userInfo = new UserInfo(); userInfo.setName(userEntity.getName()); // TODO 查詢學校信息,外部接口 UserSchool userSchool_01 = new UserSchool(); userSchool_01.setSchoolName("振華高級實驗中學"); UserSchool userSchool_02 = new UserSchool(); userSchool_02.setSchoolName("東北電力大學"); List<UserSchool> userSchoolList = new ArrayList<>(); userSchoolList.add(userSchool_01); userSchoolList.add(userSchool_02); UserRichInfo userRichInfo = new UserRichInfo(); userRichInfo.setUserInfo(userInfo); userRichInfo.setUserSchoolList(userSchoolList); return userRichInfo; } }
infrastructure/po/UserEntity.java | 數據庫對象類
public class UserEntity { private Long id; private String name; get/set ... }
infrastructrue/repository/UserRepository.java | 領域層定義接口,基礎層資源庫實現
@Repository("userRepository") public class UserRepository implements IUserRepository { @Resource(name = "userMysqlRepository") private IUserRepository userMysqlRepository; @Resource(name = "userRedisRepository") private IUserRepository userRedisRepository; @Override public void save(UserEntity userEntity) { //保存到DB userMysqlRepository.save(userEntity); //保存到Redis userRedisRepository.save(userEntity); } @Override public UserEntity query(Long id) { UserEntity userEntityRedis = userRedisRepository.query(id); if (null != userEntityRedis) return userEntityRedis; UserEntity userEntityMysql = userMysqlRepository.query(id); if (null != userEntityMysql){ //保存到Redis userRedisRepository.save(userEntityMysql); return userEntityMysql; } // 查詢為NULL return null; } }
interfaces/dto/UserInfoDto.java | DTO對象類,隔離數據庫類
public class UserInfoDto { private Long id; // ID public Long getId() { return id; } public void setId(Long id) { this.id = id; } }
interfaces/facade/DDDController.java | 門面接口
@Controller public class DDDController { @Resource(name = "userService") private UserService userService; @RequestMapping("/index") public String index(Model model) { return "index"; } @RequestMapping("/api/user/queryUserInfo") @ResponseBody public ResponseEntity queryUserInfo(@RequestBody UserInfoDto request) { return new ResponseEntity<>(userService.queryUserInfoById(request.getId()), HttpStatus.OK); } }
六、綜上總結
以上基於DDD一個基本入門的結構演示完成,實際開發可以按照此模式進行調整。目前這個架構分層還不能很好的進行分離,以及層級關系的引用還不利於擴展。
以上就是淺談Java開發架構之領域驅動設計DDD落地的詳細內容,更多關於Java開發架構 領域驅動設計DDD落地的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- SpringBoot整合Mongodb實現增刪查改的方法
- DDD框架落地實戰
- SpringBoot帶你實現一個點餐小程序
- 基於spring data jpa @query返回map的踩坑記錄
- 一文搞懂Spring中@Autowired和@Resource的區別