DDD专题案例一《初识领域驱动设计DDD落地方案》 -- 知识铺
作者:付政委
纳百川、吞吐、成自卧龙,笑红尘、纷繁、当乃胸容
微信公众号:bugstack虫洞栈
领取驱动设计DDD{Domain-Driven Design}历史较长但随着微服务的兴起DDD又活跃到开发工程师的视线。它提供的是一套架构设计思想,我们可以使用这套方法论将架构设计的尽可能做到高内聚、低耦合、可扩展性强的应用服务。那么本专题以DDD实战落地为根本,分章节设计不同的架构模型。
学习并实战是奔入应用级开发最快的方法,Hi HelloWorld!我来了。
前言介绍
DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消化领域知识,从领域知识中提取和划分为一个一个的子领域(核心子域,通用子域,支撑子域),并在子领域上建立模型,再重复以上步骤,这样周而复始,构建出一套符合当前领域的模型。
微信公众号:bugstack虫洞栈 | DDD概述
开发目标
依靠领域驱动设计的设计思想,通过事件风暴建立领域模型,合理划分领域逻辑和物理边界,建立领域对象及服务矩阵和服务架构图,定义符合DDD分层架构思想的代码结构模型,保证业务模型与代码模型的一致性。通过上述设计思想、方法和过程,指导团队按照DDD设计思想完成微服务设计和开发。
1、拒绝泥球小单体、拒绝污染功能与服务、拒绝一加功能排期一个月
2、架构出高可用极易符合互联网高速迭代的应用服务
3、物料化、组装化、可编排的服务,提高人效
服务架构
微信公众号:bugstack虫洞栈 | 服务架构
-
应用层{application}
-
应用服务位于应用层。用来表述应用和用户行为,负责服务的组合、编排和转发,负责处理业务用例的执行顺序以及结果的拼装。
-
应用层的服务包括应用服务和领域事件相关服务。
-
应用服务可对微服务内的领域服务以及微服务外的应用服务进行组合和编排,或者对基础层如文件、缓存等数据直接操作形成应用服务,对外提供粗粒度的服务。
-
领域事件服务包括两类:领域事件的发布和订阅。通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦。
-
领域层{domain}
-
领域服务位于领域层,为完成领域中跨实体或值对象的操作转换而封装的服务,领域服务以与实体和值对象相同的方式参与实施过程。
-
领域服务对同一个实体的一个或多个方法进行组合和封装,或对多个不同实体的操作进行组合或编排,对外暴露成领域服务。领域服务封装了核心的业务逻辑。实体自身的行为在实体类内部实现,向上封装成领域服务暴露。
-
为隐藏领域层的业务逻辑实现,所有领域方法和服务等均须通过领域服务对外暴露。
-
为实现微服务内聚合之间的解耦,原则上禁止跨聚合的领域服务调用和跨聚合的数据相互关联。
-
基础层{infrastructrue}
-
基础服务位于基础层。为各层提供资源服务(如数据库、缓存等),实现各层的解耦,降低外部资源变化对业务逻辑的影响。
-
基础服务主要为仓储服务,通过依赖反转的方式为各层提供基础资源服务,领域服务和应用服务调用仓储服务接口,利用仓储实现持久化数据对象或直接访问基础资源。
-
接口层{interfaces}
-
接口服务位于用户接口层,用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给应用层。
开发环境
1、jdk1.8【jdk1.7以下只能部分支持netty】
2、springboot 2.0.6.RELEASE
3、idea + maven
代码示例
1itstack-demo-ddd-01
2└── src
3 ├── main
4 │ ├── java
5 │ │ └── org.itstack.demo
6 │ │ ├── application
7 │ │ │ ├── event
8 │ │ │ │ └── ApplicationRunner.java
9 │ │ │ └── service
10 │ │ │ └── UserService.java
11 │ │ ├── domain
12 │ │ │ ├── model
13 │ │ │ │ ├── aggregates
14 │ │ │ │ │ └── UserRichInfo.java
15 │ │ │ │ └── vo
16 │ │ │ │ ├── UserInfo.java
17 │ │ │ │ └── UserSchool.java
18 │ │ │ ├── repository
19 │ │ │ │ └── IuserRepository.java
20 │ │ │ └── service
21 │ │ │ └── UserServiceImpl.java
22 │ │ ├── infrastructure
23 │ │ │ ├── dao
24 │ │ │ │ ├── impl
25 │ │ │ │ │ └── UserDaoImpl.java
26 │ │ │ │ └── UserDao.java
27 │ │ │ ├── po
28 │ │ │ │ └── UserEntity.java
29 │ │ │ ├── repository
30 │ │ │ │ ├── mysql
31 │ │ │ │ │ └── UserMysqlRepository.java
32 │ │ │ │ ├── redis
33 │ │ │ │ │ └── UserRedisRepository.java
34 │ │ │ │ └── UserRepository.java
35 │ │ │ └── util
36 │ │ │ └── RdisUtil.java
37 │ │ ├── interfaces
38 │ │ │ ├── dto
39 │ │ │ │ └── UserInfoDto.java
40 │ │ │ └── facade
41 │ │ │ └── DDDController.java
42 │ │ └── DDDApplication.java
43 │ ├── resources
44 │ │ └── application.yml
45 │ └── webapp
46 │ └── WEB-INF
47 │ └── index.jsp
48 └── test
49 └── java
50 └── org.itstack.demo.test
51 └── ApiTest.java
演示部分重点代码块,完整代码下载关注公众号;bugstack虫洞栈 | 回复DDD落地
application/UserService.java | 应用层用户服务,领域层服务做具体实现
1/**
2 * 应用层用户服务
3 * 虫洞栈:https://bugstack.cn
4 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
5 * Create by fuzhengwei on @2019
6 */
7public interface UserService {
8
9 UserRichInfo queryUserInfoById(Long id);
10
11}
domain/repository/IuserRepository.java | 领域层资源库,由基础层实现
1/**
2 * 虫洞栈:https://bugstack.cn
3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
4 * Create by fuzhengwei on @2019
5 */
6public interface IUserRepository {
7
8 void save(UserEntity userEntity);
9
10 UserEntity query(Long id);
11
12}
domain/service/UserServiceImpl.java | 应用层实现类,应用层是很薄的一层可以只做服务编排
1/**
2 * 虫洞栈:https://bugstack.cn
3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
4 * Create by fuzhengwei on @2019
5 */
6@Service("userService")
7public class UserServiceImpl implements UserService {
8
9 @Resource(name = "userRepository")
10 private IUserRepository userRepository;
11
12 @Override
13 public UserRichInfo queryUserInfoById(Long id) {
14
15 // 查询资源库
16 UserEntity userEntity = userRepository.query(id);
17
18 UserInfo userInfo = new UserInfo();
19 userInfo.setName(userEntity.getName());
20
21 // TODO 查询学校信息,外部接口
22 UserSchool userSchool_01 = new UserSchool();
23 userSchool_01.setSchoolName("振华高级实验中学");
24
25 UserSchool userSchool_02 = new UserSchool();
26 userSchool_02.setSchoolName("东北电力大学");
27
28 List<UserSchool> userSchoolList = new ArrayList<>();
29 userSchoolList.add(userSchool_01);
30 userSchoolList.add(userSchool_02);
31
32 UserRichInfo userRichInfo = new UserRichInfo();
33 userRichInfo.setUserInfo(userInfo);
34 userRichInfo.setUserSchoolList(userSchoolList);
35
36 return userRichInfo;
37 }
38
39}
infrastructure/po/UserEntity.java | 数据库对象类
1/**
2 * 数据库实体对象;用户实体
3 * 虫洞栈:https://bugstack.cn
4 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
5 * Create by fuzhengwei on @2019
6 */
7public class UserEntity {
8
9 private Long id;
10 private String name;
11
12 get/set ...
13}
infrastructrue/repository/UserRepository.java | 领域层定义接口,基础层资源库实现
1/**
2 * 虫洞栈:https://bugstack.cn
3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
4 * Create by fuzhengwei on @2019
5 */
6@Repository("userRepository")
7public class UserRepository implements IUserRepository {
8
9 @Resource(name = "userMysqlRepository")
10 private IUserRepository userMysqlRepository;
11
12 @Resource(name = "userRedisRepository")
13 private IUserRepository userRedisRepository;
14
15 @Override
16 public void save(UserEntity userEntity) {
17 //保存到DB
18 userMysqlRepository.save(userEntity);
19
20 //保存到Redis
21 userRedisRepository.save(userEntity);
22 }
23
24 @Override
25 public UserEntity query(Long id) {
26
27 UserEntity userEntityRedis = userRedisRepository.query(id);
28 if (null != userEntityRedis) return userEntityRedis;
29
30 UserEntity userEntityMysql = userMysqlRepository.query(id);
31 if (null != userEntityMysql){
32 //保存到Redis
33 userRedisRepository.save(userEntityMysql);
34 return userEntityMysql;
35 }
36
37 // 查询为NULL
38 return null;
39 }
40
41}
interfaces/dto/UserInfoDto.java | DTO对象类,隔离数据库类
1/**
2 * 虫洞栈:https://bugstack.cn
3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
4 * Create by fuzhengwei on @2019
5 */
6public class UserInfoDto {
7
8 private Long id; // ID
9
10 public Long getId() {
11 return id;
12 }
13
14 public void setId(Long id) {
15 this.id = id;
16 }
17
18}
interfaces/facade/DDDController.java | 门面接口
1/**
2 * 虫洞栈:https://bugstack.cn
3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
4 * Create by fuzhengwei on @2019
5 */
6@Controller
7public class DDDController {
8
9 @Resource(name = "userService")
10 private UserService userService;
11
12 @RequestMapping("/index")
13 public String index(Model model) {
14 return "index";
15 }
16
17 @RequestMapping("/api/user/queryUserInfo")
18 @ResponseBody
19 public ResponseEntity queryUserInfo(@RequestBody UserInfoDto request) {
20 return new ResponseEntity<>(userService.queryUserInfoById(request.getId()), HttpStatus.OK);
21 }
22
23}
综上总结
-
以上基于DDD一个基本入门的结构演示完成,实际开发可以按照此模式进行调整。
-
目前这个架构分层还不能很好的进行分离,以及层级关系的引用还不利于扩展。
-
后续会持续完善以及可以组合搭建RPC框架等,让整个架构更利于互联网开发。
微信公众号:bugstack虫洞栈,欢迎关注&获取源码
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek001/post/20240710/DDD%E4%B8%93%E9%A2%98%E6%A1%88%E4%BE%8B%E4%B8%80%E5%88%9D%E8%AF%86%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1DDD%E8%90%BD%E5%9C%B0%E6%96%B9%E6%A1%88--%E7%9F%A5%E8%AF%86%E9%93%BA/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com