浅谈Java开发架构之领域驱动设计DDD落地

 更新时间:2021年06月18日 15:25:05   作者:小傅哥  
DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题

一、前言

整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(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落地的资料请关注脚本之家其它相关文章!

相关文章

  • 深入浅析Java 抽象类和接口

    深入浅析Java 抽象类和接口

    这篇文章主要介绍了Java 抽象类和接口的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-11-11
  • springcloud微服务之Eureka配置详解

    springcloud微服务之Eureka配置详解

    这篇文章主要介绍了springcloud微服务之Eureka配置详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Java如何实现树的同构?

    Java如何实现树的同构?

    今天给大家带来的是关于Java的相关知识,文章围绕着Java如何实现树的同构展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java使用Cipher类实现加密的过程详解

    Java使用Cipher类实现加密的过程详解

    这篇文章主要介绍了Java使用Cipher类实现加密的过程详解,Cipher类提供了加密和解密的功能,创建密匙主要使用SecretKeySpec、KeyGenerator和KeyPairGenerator三个类来创建密匙。感兴趣可以了解一下
    2020-07-07
  • Spring实战之协调作用域不同步的Bean操作示例

    Spring实战之协调作用域不同步的Bean操作示例

    这篇文章主要介绍了Spring实战之协调作用域不同步的Bean操作,结合实例形式分析了Spring协调作用域不同步的Bean相关配置及使用技巧,需要的朋友可以参考下
    2019-11-11
  • Java中计算时间差的方法

    Java中计算时间差的方法

    这篇文章主要介绍了Java中计算时间差的方法,实例分析了java常见的三种计算时间差的技巧,需要的朋友可以参考下
    2015-06-06
  • 详解Java中==和equals()的区别

    详解Java中==和equals()的区别

    这篇文章主要介绍了Java中==和equals()的区别,,==可以使用在基本数据类型变量和引用数据类型变量中,equals()是方法,只能用于引用数据类型,需要的朋友可以参考下
    2021-11-11
  • 简单验证码生成Java版

    简单验证码生成Java版

    这篇文章主要为大家详细介绍了简单验证码生成Java版,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Spring整合Mycat2的具体过程详解

    Spring整合Mycat2的具体过程详解

    这篇文章主要给大家介绍Springboot整合Mycat2的具体过程,文中有详细的图解过程,感兴趣的小伙伴可以跟着小编一起来学习
    2023-05-05
  • Dubbo服务无法注册到ZK上问题

    Dubbo服务无法注册到ZK上问题

    这篇文章主要介绍了Dubbo服务无法注册到ZK上问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05

最新评论