DDD专题案例一《初识领域驱动设计DDD落地方案》

Wesley13
• 阅读 1138

DDD专题案例一《初识领域驱动设计DDD落地方案》

作者:付政委

纳百川、吞吐、成自卧龙,笑红尘、纷繁、当乃胸容

微信公众号:bugstack虫洞栈
领取驱动设计DDD{Domain-Driven Design}历史较长但随着微服务的兴起DDD又活跃到开发工程师的视线。它提供的是一套架构设计思想,我们可以使用这套方法论将架构设计的尽可能做到高内聚、低耦合、可扩展性强的应用服务。那么本专题以DDD实战落地为根本,分章节设计不同的架构模型。
学习并实战是奔入应用级开发最快的方法,Hi HelloWorld!我来了。

前言介绍

DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消化领域知识,从领域知识中提取和划分为一个一个的子领域(核心子域,通用子域,支撑子域),并在子领域上建立模型,再重复以上步骤,这样周而复始,构建出一套符合当前领域的模型。

DDD专题案例一《初识领域驱动设计DDD落地方案》

微信公众号:bugstack虫洞栈 | DDD概述

开发目标

依靠领域驱动设计的设计思想,通过事件风暴建立领域模型,合理划分领域逻辑和物理边界,建立领域对象及服务矩阵和服务架构图,定义符合DDD分层架构思想的代码结构模型,保证业务模型与代码模型的一致性。通过上述设计思想、方法和过程,指导团队按照DDD设计思想完成微服务设计和开发。
1、拒绝泥球小单体、拒绝污染功能与服务、拒绝一加功能排期一个月
2、架构出高可用极易符合互联网高速迭代的应用服务
3、物料化、组装化、可编排的服务,提高人效

服务架构

DDD专题案例一《初识领域驱动设计DDD落地方案》

微信公众号: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    │   │       │    └── service10    │   │       │        └── UserService.java    11    │   │       ├── domain12    │   │       │    ├── model13    │   │       │    │   ├── aggregates14    │   │       │    │   │   └── UserRichInfo.java   15    │   │       │    │   └── vo16    │   │       │    │       ├── UserInfo.java   17    │   │       │    │       └── UserSchool.java 18    │   │       │    ├── repository19    │   │       │    │   └── IuserRepository.java    20    │   │       │    └── service21    │   │       │        └── UserServiceImpl.java    22    │   │       ├── infrastructure23    │   │       │    ├── dao24    │   │       │    │   ├── impl25    │   │       │    │   │   └── UserDaoImpl.java    26    │   │       │    │   └── UserDao.java    27    │   │       │    ├── po28    │   │       │    │   └── UserEntity.java 29    │   │       │    ├── repository30    │   │       │    │   ├── mysql31    │   │       │    │   │   └── UserMysqlRepository.java32    │   │       │    │   ├── redis33    │   │       │    │   │   └── UserRedisRepository.java        34    │   │       │    │   └── UserRepository.java 35    │   │       │    └── util36    │   │       │        └── RdisUtil.java37    │   │       ├── interfaces38    │   │       │    ├── dto39    │   │       │    │   └── UserInfoDto.java    40    │   │       │    └── facade41    │   │       │        └── DDDController.java42    │   │       └── DDDApplication.java43    │   ├── resources    44    │   │   └── application.yml45    │   └── webapp    46    │       └── WEB-INF47    │            └── index.jsp   48    └── test49         └── java50             └── org.itstack.demo.test51                 └── 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);1011}

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); 910    UserEntity query(Long id);1112}

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;1112    @Override13    public UserRichInfo queryUserInfoById(Long id) {1415        // 查询资源库16        UserEntity userEntity = userRepository.query(id);1718        UserInfo userInfo = new UserInfo();19        userInfo.setName(userEntity.getName());2021        // TODO 查询学校信息,外部接口22        UserSchool userSchool_01 = new UserSchool();23        userSchool_01.setSchoolName("振华高级实验中学");2425        UserSchool userSchool_02 = new UserSchool();26        userSchool_02.setSchoolName("东北电力大学");2728        List<UserSchool> userSchoolList = new ArrayList<>();29        userSchoolList.add(userSchool_01);30        userSchoolList.add(userSchool_02);3132        UserRichInfo userRichInfo = new UserRichInfo();33        userRichInfo.setUserInfo(userInfo);34        userRichInfo.setUserSchoolList(userSchoolList);3536        return userRichInfo;37    }3839}

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;1112    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;1112    @Resource(name = "userRedisRepository")13    private IUserRepository userRedisRepository;1415    @Override16    public void save(UserEntity userEntity) {17        //保存到DB18        userMysqlRepository.save(userEntity);1920        //保存到Redis21        userRedisRepository.save(userEntity);22    }2324    @Override25    public UserEntity query(Long id) {2627        UserEntity userEntityRedis = userRedisRepository.query(id);28        if (null != userEntityRedis) return userEntityRedis;2930        UserEntity userEntityMysql = userMysqlRepository.query(id);31        if (null != userEntityMysql){32            //保存到Redis33            userRedisRepository.save(userEntityMysql);34            return userEntityMysql;35        }3637        // 查询为NULL38        return null;39    }4041}

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 910    public Long getId() {11        return id;12    }1314    public void setId(Long id) {15        this.id = id;16    }1718}

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;1112    @RequestMapping("/index")13    public String index(Model model) {14        return "index";15    }1617    @RequestMapping("/api/user/queryUserInfo")18    @ResponseBody19    public ResponseEntity queryUserInfo(@RequestBody UserInfoDto request) {20        return new ResponseEntity<>(userService.queryUserInfoById(request.getId()), HttpStatus.OK);21    }2223}

综上总结

  • 以上基于DDD一个基本入门的结构演示完成,实际开发可以按照此模式进行调整。

  • 目前这个架构分层还不能很好的进行分离,以及层级关系的引用还不利于扩展。

  • 后续会持续完善以及可以组合搭建RPC框架等,让整个架构更利于互联网开发。


DDD专题案例一《初识领域驱动设计DDD落地方案》

微信公众号:bugstack虫洞栈,欢迎关注&获取源码

本文分享自微信公众号 - bugstack虫洞栈(bugstack)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
DDD专题案例三《领域驱动设计架构基于SpringCloud搭建微服务》
!(https://oscimg.oschina.net/oscnet/ea8c4fbbc514341be35cc89aa9874e02209.jpg)作者:付政委成长总是来自于对未知领域的探索| 库布齐50公里穿行微信公众号:bugstack虫洞栈|关注获取源码沉淀、分享、成长,专注于原创专题案例,以最易学习编程的方式分
Stella981 Stella981
3年前
Spring Cloud(六)《基于github webhook动态刷新服务配置》
!(https://oscimg.oschina.net/oscnet/e4b593359aa1dfd890f72b82551627f5e6a.jpg)作者:付政委自诚明,谓之性;自明诚,谓之教微信公众号:bugstack虫洞栈沉淀、分享、成长,专注于原创专题案例,以最易学习编程的方式分享知识,让自己和他人都能有所收获。目前
Wesley13 Wesley13
3年前
030 SSM综合练习06
1.权限操作涉及的三张表(1)用户表信息描述users!(https://oscimg.oschina.net/oscnet/a4a2b1f943cbc2db1c8ddd613e7ed00a9ae.png)sql语句:CREATETABLEusers(idVARCHAR2(32)DEFAU
Wesley13 Wesley13
3年前
DDD领域驱动设计
C进阶系列——DDD领域驱动设计初探(七):Web层的搭建(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.cnblogs.com%2Flandeanfen%2Fp%2F4920577.html)C进阶系列——DDD领域驱动设计初探(六):领域服务(https://w
Wesley13 Wesley13
3年前
DDD 领域驱动设计使微服务更好地落地
!(https://oscimg.oschina.net/oscnet/2e0cb8f726f146669f1c4aacfb327d52.png)DDD介绍DDD(领域驱动设计)早在2003年就被提出,但当时国内开发环境较为单一,完全用不到DDD,也就没有团队去研究和布道。最近几年,
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
郑文 郑文
8个月前
DDD(领域驱动设计)思想解读及优秀实践
DDD(领域驱动设计)思想解读及优秀实践download》quangneng.com/1964/DDD是什么DDD(DomainDrivenDesign,领域驱动设计)是一种软件开发方法论,它提供了一种方式来设计软件应用程序,以满足复杂需求。该方法将重点放