Java开发架构篇《初识领域驱动设计DDD落地》
作者:小傅哥
博客:https://bugstack.cn
沉淀、分享、成长,让自己和他人都能有所收获!
一、前言
DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消化领域知识,从领域知识中提取和划分为一个一个的子领域(核心子域,通用子域,支撑子域),并在子领域上建立模型,再重复以上步骤,这样周而复始,构建出一套符合当前领域的模型。
二、开发目标
依靠领域驱动设计的设计思想,通过事件风暴建立领域模型,合理划分领域逻辑和物理边界,建立领域对象及服务矩阵和服务架构图,定义符合DDD分层架构思想的代码结构模型,保证业务模型与代码模型的一致性。通过上述设计思想、方法和过程,指导团队按照DDD设计思想完成微服务设计和开发。
1、拒绝泥球小单体、拒绝污染功能与服务、拒绝一加功能排期一个月
2、架构出高可用极易符合互联网高速迭代的应用服务
3、物料化、组装化、可编排的服务,提高人效
三、服务架构
应用层{application}
- 应用服务位于应用层。用来表述应用和用户行为,负责服务的组合、编排和转发,负责处理业务用例的执行顺序以及结果的拼装。
- 应用层的服务包括应用服务和领域事件相关服务。
- 应用服务可对微服务内的领域服务以及微服务外的应用服务进行组合和编排,或者对基础层如文件、缓存等数据直接操作形成应用服务,对外提供粗粒度的服务。
- 领域事件服务包括两类:领域事件的发布和订阅。通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦。
领域层{domain}
- 领域服务位于领域层,为完成领域中跨实体或值对象的操作转换而封装的服务,领域服务以与实体和值对象相同的方式参与实施过程。
- 领域服务对同一个实体的一个或多个方法进行组合和封装,或对多个不同实体的操作进行组合或编排,对外暴露成领域服务。领域服务封装了核心的业务逻辑。实体自身的行为在实体类内部实现,向上封装成领域服务暴露。
- 为隐藏领域层的业务逻辑实现,所有领域方法和服务等均须通过领域服务对外暴露。
- 为实现微服务内聚合之间的解耦,原则上禁止跨聚合的领域服务调用和跨聚合的数据相互关联。
基础层{infrastructrue}
- 基础服务位于基础层。为各层提供资源服务(如数据库、缓存等),实现各层的解耦,降低外部资源变化对业务逻辑的影响。
- 基础服务主要为仓储服务,通过依赖反转的方式为各层提供基础资源服务,领域服务和应用服务调用仓储服务接口,利用仓储实现持久化数据对象或直接访问基础资源。
接口层{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
演示部分重点代码块,完整代码下载关注公众号;bugstack虫洞栈 | 回复DDD落地
application/UserService.java | 应用层用户服务,领域层服务做具体实现
/**
* 应用层用户服务
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public interface UserService {
UserRichInfo queryUserInfoById(Long id);
}
domain/repository/IuserRepository.java | 领域层资源库,由基础层实现
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public interface IUserRepository {
void save(UserEntity userEntity);
UserEntity query(Long id);
}
domain/service/UserServiceImpl.java | 应用层实现类,应用层是很薄的一层可以只做服务编排
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@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 | 数据库对象类
/**
* 数据库实体对象;用户实体
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public class UserEntity {
private Long id;
private String name;
get/set ...
}
infrastructrue/repository/UserRepository.java | 领域层定义接口,基础层资源库实现
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@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对象类,隔离数据库类
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public class UserInfoDto {
private Long id; // ID
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
interfaces/facade/DDDController.java | 门面接口
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@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一个基本入门的结构演示完成,实际开发可以按照此模式进行调整。
- 目前这个架构分层还不能很好的进行分离,以及层级关系的引用还不利于扩展。
- 后续会持续完善以及可以组合搭建RPC框架等,让整个架构更利于互联网开发。
七、推荐阅读
Java开发架构篇《初识领域驱动设计DDD落地》的更多相关文章
- Java开发架构篇:领域驱动设计架构基于SpringCloud搭建微服务
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 微服务不是泥球小单体,而是具备更加清晰职责边界的完整一体的业务功能服务.领域驱动 ...
- 基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式
-之动态查询,查询逻辑封装复用 基于领域驱动设计(DDD)超轻量级快速开发架构详细介绍请看 https://www.cnblogs.com/neozhu/p/13174234.html 需求 配合Ea ...
- python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))
昨日内容回顾 1. 三个类 ChangeList,封装列表页面需要的所有数据. StarkConfig,生成URL和视图对应关系 + 默认配置 AdminSite,用于保存 数据库类 和 处理该类的对 ...
- 领域驱动设计(DDD)
领域驱动设计(DDD)实现之路 2004年,当Eric Evans的那本<领域驱动设计——软件核心复杂性应对之道>(后文简称<领域驱动设计>)出版时,我还在念高中,接触到领域驱 ...
- 关于领域驱动设计 DDD(Domain-Driven Design)
以下旨在 理解DDD. 1. 什么是领域? 妈妈好是做母婴新零售的产品,应该属于电商平台,那么电商平台就是一个领域. 同一个领域的系统都有相同的核心业务. eg: 电商领域都有:商品浏览.购物 ...
- 领域驱动设计(DDD:Domain-Driven Design)
领域驱动设计(DDD:Domain-Driven Design) Eric Evans的"Domain-Driven Design领域驱动设计"简称DDD,Evans DDD是一套 ...
- Java开发架构篇:DDD模型领域层决策规则树服务设计
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一章节介绍了领域驱动设计的基本概念以及按照领域驱动设计的思想进行代码分层,但是仅 ...
- 如何使用ABP进行软件开发(2) 领域驱动设计和三层架构的对比
简述 上一篇简述了ABP框架中的一些基础理论,包括ABP前后端项目的分层结构,以及后端项目中涉及到的知识点,例如DTO,应用服务层,整洁架构,领域对象(如实体,聚合,值对象)等. 笔者也曾经提到,AB ...
- 基于领域驱动设计(DDD)超轻量级快速开发架构
smartadmin.core.urf 这个项目是基于asp.net core 3.1(最新)基础上参照领域驱动设计(DDD)的理念,并参考目前最为了流行的abp架构开发的一套轻量级的快速开发web ...
随机推荐
- 获取某个时间开始 之后的 N次[周几,周几]
废话不多说,直接上菜! 调用函数代码举例 //PS :这里需要注意的是 周日 是 0 !!!!! console.log(getBeforeDate(-10000)) //一万天之后的日期 conso ...
- 使用 GoLand 启动 运行 Go 项目
来源:https://my.oschina.net/u/3744526/blog/3085468 在使用本博客经验之前 需配置好 GOPATH 跟 GOROOT 创建好本地工作路径之后,使用 GoLa ...
- cdn服务器
CDN的基本原理和基础架构 CDN是将源站内容分发至最接近用户的节点,使用户可就近取得所需内容,提高用户访问的响应速度和成功率.解决因分布.带宽.服务器性能带来的访问延迟问题,适用于站点加速.点播.直 ...
- 文件包含漏洞(pikachu)
文件包含漏洞 在web后台开发中,程序员往往为了提高效率以及让代码看起来更加简洁,会使用'包含'函数功能,比如把一系列功能函数都写进function.php中,之后当某个文件需要调用的时候,就直接在文 ...
- CG-CTF(2)
CG-CTF https://cgctf.nuptsast.com/challenges#Web 续上~ 第七题:单身二十年 查看源代码: 取得flag(干杯~): 本题也可通过burp抓包,查看返回 ...
- 利用python画出SJF调度图
最先发布在csdn.本人原创. https://blog.csdn.net/weixin_43906799/article/details/105510046 SJF算法: 最短作业优先(SJF)调度 ...
- Maven+Jmeter+Jenkins的持续集成的新尝试
前言: 这又是一篇迟到很久的文章,四月身体欠佳,根本不在状态. 好了,回到正题,相信大家也在很多博客,看过很多类似乎的文章,那么大家来看看我是如何实现的? 准备工作: 创建一个maven工程 创建一个 ...
- 1月份中国综合PMI指数为53.2% 企业生产经营活动总体增速加快
中新社北京1月31日电 (记者 王恩博)中国国家统计局31日发布数据显示,2019年1月份,中国综合PMI产出指数为53.2%,比上月上升0.6个百分点,表明中国企业生产经营活动总体增速加快. 其中, ...
- unix域源码解析
首先我们先要创建一个用于通信的结构unix_proto_data ,并初始化某些字段 static int unix_proto_create(struct socket *sock, int pro ...
- Clickhouse 时区转换
Clickhouse 时区转换 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS). OLAP场景的关键特征 大多数是读请求 数据总是以相当大的批(> 1000 ...