基于DDD的微服务落地( 二 )

在应用服务组合不同聚合的领域服务时 , 通过Id或参数传参 , 尽量避免领域对象传参 , 以减少聚合之间的耦合度 。
领域事件
领域事件基类
@Datapublic class DomainEvent {String id;Date timestamp;String source;String data;}@Servicepublic class EventPublisher {public void publish(LeaveEvent event){//send to MQ//mq.send(event);}}领域事件实体
@Datapublic class LeaveEvent extends DomainEvent {LeaveEventType leaveEventType;public static LeaveEvent create(LeaveEventType eventType, Leave leave){LeaveEvent event = new LeaveEvent();event.setId(IdGenerator.nextId());event.setLeaveEventType(eventType);event.setTimestamp(new Date());event.setData(JSON.toJSONString(leave));return event;}}领域事件的执行逻辑:

  1. 执行业务逻辑 , 产生领域事件 。
  2. 调用仓储接口 , 完成业务数据持久化 。
  3. 调用仓储接口 , 完成事件数据持久化 。
  4. 完成领域事件发布 。
仓储模式
仓储接口
public interface ILeaveRepository {void save(LeavePO leavePO);void saveEvent(LeaveEventPO leaveEventPO);LeavePO findById(String id);List<LeavePO> queryByApplicantId(String applicantId);List<LeavePO> queryByApproverId(String approverId);}仓储实现
@Repositorypublic class LeaveRepositoryImpl implements ILeaveRepository {@AutowiredLeaveDao leaveDao;@AutowiredApprovalInfoDao approvalInfoDao;@AutowiredLeaveEventDao leaveEventDao;public void save(LeavePO leavePO) {leaveDao.save(leavePO);leavePO.getHistoryApprovalInfoPOList().forEach(approvalInfoPO -> approvalInfoPO.setLeaveId(leavePO.getId()));approvalInfoDao.saveAll(leavePO.getHistoryApprovalInfoPOList());}public void saveEvent(LeaveEventPO leaveEventPO){leaveEventDao.save(leaveEventPO);}@Overridepublic LeavePO findById(String id) {return leaveDao.findById(id).orElseThrow(() -> new RuntimeException("leave不存在"));}@Overridepublic List<LeavePO> queryByApplicantId(String applicantId) {List<LeavePO> leavePOList = leaveDao.queryByApplicantId(applicantId);leavePOList.forEach(leavePO -> {List<ApprovalInfoPO> approvalInfoPOList = approvalInfoDao.queryByLeaveId(leavePO.getId());leavePO.setHistoryApprovalInfoPOList(approvalInfoPOList);});return leavePOList;}@Overridepublic List<LeavePO> queryByApproverId(String approverId) {List<LeavePO> leavePOList = leaveDao.queryByApproverId(approverId);leavePOList.forEach(leavePO -> {List<ApprovalInfoPO> approvalInfoPOList = approvalInfoDao.queryByLeaveId(leavePO.getId());leavePO.setHistoryApprovalInfoPOList(approvalInfoPOList);});return leavePOList;}}这里为什么没有使用一对多、多对对呢?时间紧任务重或者并发量不高时可以使用 , 后期并发量起来了后 , 数据库将成为瓶颈 。
JPA/Hibernate注解:@.NEToMany、@ManyToOne、@ManyToMany;
MyBatis注解:
@Results(id="", value=https://www.isolves.com/it/cxkf/kj/2023-03-10/{@Result(column="", property="", jdbcType=JdbcType.INTEGER),
@Result(column="", property="", JAVAType=xx.class,one=@One(select="com.xx..XxMapper.selectById"))
})

@Results(id="",value = https://www.isolves.com/it/cxkf/kj/2023-03-10/{ @Result(property = "", column = ""),
@Result(property = "xxList", javaType=List.class, many=@Many(select=""), column = "")});
Mybatis xml: association、collection 。
 
工厂模式
工厂模式将与业务无关的职能从聚合根中剥离 , 放在工厂中统一创建和初始化 。
//可考虑使用MapStruct@Servicepublic class LeaveFactory {public LeavePO createLeavePO(Leave leave) {LeavePO leavePO = new LeavePO();leavePO.setId(UUID.randomUUID().toString());leavePO.setApplicantId(leave.getApplicant().getPersonId());leavePO.setApplicantName(leave.getApplicant().getPersonName());leavePO.setApproverId(leave.getApprover().getPersonId());leavePO.setApproverName(leave.getApprover().getPersonName());leavePO.setStartTime(leave.getStartTime());leavePO.setStatus(leave.getStatus());List<ApprovalInfoPO> historyApprovalInfoPOList = approvalInfoPOListFromDO(leave);leavePO.setHistoryApprovalInfoPOList(historyApprovalInfoPOList);return leavePO;}public Leave getLeave(LeavePO leavePO) {Leave leave = new Leave();Applicant applicant = Applicant.builder().personId(leavePO.getApplicantId()).personName(leavePO.getApplicantName()).build();leave.setApplicant(applicant);Approver approver = Approver.builder().personId(leavePO.getApproverId()).personName(leavePO.getApproverName()).build();leave.setApprover(approver);leave.setStartTime(leavePO.getStartTime());leave.setStatus(leavePO.getStatus());List<ApprovalInfo> approvalInfos = getApprovalInfos(leavePO.getHistoryApprovalInfoPOList());leave.setHistoryApprovalInfos(approvalInfos);return leave;}public LeaveEventPO createLeaveEventPO(LeaveEvent leaveEvent){LeaveEventPO eventPO = new LeaveEventPO();eventPO.setLeaveEventType(leaveEvent.getLeaveEventType());eventPO.setSource(leaveEvent.getSource());eventPO.setTimestamp(leaveEvent.getTimestamp());eventPO.setData(JSON.toJSONString(leaveEvent.getData()));return eventPO;}private List<ApprovalInfoPO> approvalInfoPOListFromDO(Leave leave) {return leave.getHistoryApprovalInfos().stream().map(this::approvalInfoPOFromDO).collect(Collectors.toList());}private ApprovalInfoPO approvalInfoPOFromDO(ApprovalInfo approvalInfo){ApprovalInfoPO po = new ApprovalInfoPO();po.setApproverId(approvalInfo.getApprover().getPersonId());po.setApproverLevel(approvalInfo.getApprover().getLevel());po.setApproverName(approvalInfo.getApprover().getPersonName());po.setApprovalInfoId(approvalInfo.getApprovalInfoId());po.setMsg(approvalInfo.getMsg());po.setTime(approvalInfo.getTime());return po;}private ApprovalInfo approvalInfoFromPO(ApprovalInfoPO approvalInfoPO){ApprovalInfo approvalInfo = new ApprovalInfo();approvalInfo.setApprovalInfoId(approvalInfoPO.getApprovalInfoId());Approver approver = Approver.builder().personId(approvalInfoPO.getApproverId()).personName(approvalInfoPO.getApproverName()).level(approvalInfoPO.getApproverLevel()).build();approvalInfo.setApprover(approver);approvalInfo.setMsg(approvalInfoPO.getMsg());approvalInfo.setTime(approvalInfoPO.getTime());return approvalInfo;} private List<ApprovalInfo> getApprovalInfos(List<ApprovalInfoPO> approvalInfoPOList){return approvalInfoPOList.stream().map(this::approvalInfoFromPO).collect(Collectors.toList());}}


推荐阅读