作者:小傅哥
博客: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.RELEASEidea + 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 /@Controllerpublic 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框架等,让全体架构更利于互联网开拓。