分包示例

以界限上线文为指导核心,总体分为两类 :业务界限上线文,系统界限上下文
系统界限上下文
用于放置: aop切面,通过工具包(utils),共用三方组件(mq,redis,id生成器)
业务界限上下文
按照领域划分,每个领域有一个独立的界限上线文
controller:控制器
又叫北向网关,只能将功能委托applicaton或者 reposity实现,自身只承担数据转换适配
application: 应用服务
对domain server 进行编排,控制事务,发送消息,不实现业务逻辑。需要将功能委托domain或者reposity实现
assembler
用作 DTO和do对象转换,组织网关层的数据对象(DTO,VO)入侵domain层
实例
1:验证展现层的输入
2 :将展现层对象转出领域理解的对象
3 :从reposiory获取领域对象
4: 委托领域对象执行业务处理
5:委托基础设施服务,如发送应用消息或者web调用
domain 领域
service:领域服务
- 一个现实领域动作,但是并不能归属于某个领域对象,它本身可以实现业务逻辑。但是不能窃取领域对象自身的业务逻辑
- 领域服务负责动作编排,可以调用多个聚合根,可以调用其它领域对象
如何判断一系列交互是否属于领域
1.这种情况总是出现吗?
2.这些步骤无法分开吗?
如果这些步骤必须一起出现,就不存在’任务编排‘。他们本质上是一个整体,只是因为单一职责和分治原则需要分解,做到各个对象各司其职
entity 实体
核心业务对象,有唯一标识,有自身的数据和动作。内部的数据完全由自身掌控,不可透传给其它对象。对象的状态完全通过动作来进行驱动
value 值对象
通过属性而不是ID来标识和区分,是不可变对象
factory 对象工厂
复杂对象创建
reposity 仓储
-
负责持久化数据数据对象
-
从持久化介质构建领域对象,如果对象负责委托factory进行创建
-
对于简单数据请求直接返回数据对象(PO)
repoisotry如何注入到domain中? 通过Factory 构建domain对象时设置
聚合根、实体、值对象对象之间如何建立关联
聚合根: 它本身不是具体的存在,它只是标识了一些作为跟对象的实体。就是说如果一个实体维护了一个领域边界,它内部包含了一些实体或者值对象,这个实体是外界访问内部信息的的唯一入口。
聚合要保持不变性
对象本身有一套对自身状态进行校验的检查条件,以确保该对象的本质不发生改变,这称之为不变式
- 聚合根到聚合根:通过ID关联;
- 聚合根到其内部的实体,直接对象引用;
- 聚合根到值对象,直接对象引用;
- 在一个领域内部,事务可以跨多个聚合根
- 外部对象可以通过聚合根导航到内部对象的引用,但是他们只能临时引用,不能保持引用
界限上下文交互
- 网关的对象不能渗透到领域层。如 Request 要使用内部属性或者封装成BO对象domain向内部传递
- 领域对象不能渗出界限上下文。如 Oder 这个领域对象不能直接返回给 Payment 所属的界限上下文,而是要封装成Respose这样的契约消息
代码示例
public class OrderController {
private OrderAppService orderAppService;
private OrderRepository orderRepository;
public OrderResp placeOrder(OrderDto orderDto) {
OrderDo orderDo = BeanUtils.trans(orderDto, OrderDo.class);
Long orderId = orderAppService.placeOrder(orderDo);
return new OrderResp(orderId);
}
public OrderResp cancel(String orderNo) {
orderAppService.cancelOrder(orderNo);
return new OrderResp();
}
public OrderResp cancelPayment(Long orderId, Long paymentId) {
orderAppService.cancelPayment(orderId, paymentId);
return new OrderResp();
}
//直接从repo获取
public OrderDto getOrderDetailByNo(String orderNo) {
Order order = orderRepository.findByNo(orderNo);
return BeanUtils.trans(order, OrderDto.class);
}
}
public class OrderAppService {
private OrderService orderService;
private OrderRepository orderRepository;
private OrderEventBus orderEventBus;
public Long placeOrder(OrderDo orderDo) {
Order order = orderService.placeOrder(orderDo);
orderEventBus.send(new OrderEvent(EventType.PLACE.getCode(), order));
return order.getId();
}
public void cancelOrder(String orderNo) {
orderService.cancelOrder(orderNo);
orderEventBus.send(new OrderEvent(EventType.CANCEL.getCode(), orderNo));
}
public void cancelPayment(Long orderId, Long paymentId) {
Order order = orderService.cancelPayment(orderId, paymentId);
orderEventBus.send(new OrderEvent(EventType.UPDATE.getCode(), order));
}
}
public class OrderService {
private OrderRepository orderRepository;
private OrderFactory orderFactory;
@Transactional(rollbackFor = RuntimeException.class)
public Order placeOrder(OrderDo orderDo) {
Order order = orderFactory.buildFromDo(orderDo);
order.place();
return order;
}
@Transactional(rollbackFor = RuntimeException.class)
public void cancelOrder(String orderNo) {
Order order = orderRepository.findByNo(orderNo);
if (order == null) {
throw new RuntimeException("订单不存在");
}
order.cancel();
}
@Transactional(rollbackFor = RuntimeException.class)
public Order cancelPayment(Long orderId, Long paymentId) {
Order order = orderRepository.find(orderId);
if (order == null) {
throw new RuntimeException("订单不存在");
}
order.cancelPayment(paymentId);
return order;
}
}
@Data
public class Order {
private OrderRepository orderRepository;
public void place() {
if (this.money <= 0 || this.payments == null) {
throw new RuntimeException("无效订单");
}
if (orderRepository.findByNo(this.orderNo) != null) {
throw new RuntimeException("重复下单");
}
Long orderId = orderRepository.addOrder(this);
OrderDetail orderDetail = new OrderDetail();
orderDetail.orderId = orderId;
orderDetail.money = this.money;
orderDetail.status = OrderStatus.INIT.getCode();
orderRepository.addOrderDetail(orderDetail);
}
public void cancel() {
if (this.status != OrderStatus.PAY.getCode()) {
throw new RuntimeException("订单不能撤销");
}
this.status = OrderStatus.CANCELED.getCode();
orderRepository.update(this);
OrderDetail orderDetail = new OrderDetail();
orderDetail.orderId = this.id;
orderDetail.money = this.money;
orderDetail.status = OrderStatus.CANCELED.getCode();
orderRepository.addOrderDetail(orderDetail);
}
public void cancelPayment(Long paymentId) {
Payment payment = payments.stream().filter(x -> x.id.equals(paymentId)).findAny().get();
payment.cancel();
this.money = payments.stream().filter(x -> x.status != 1).mapToLong(x -> x.money).sum();
orderRepository.update(this);
orderRepository.updatePayment(payment);
}
private Long id;
private String orderNo;
private Long money;
private Integer status;
private List<Payment> payments;
}
@Getter
@AllArgsConstructor
public enum OrderStatus {
INIT(1, "未支付"),
PAYING(2, "支付中"),
PAY(3, "已支付"),
CANCELED(4, "已撤销");
private int code;
private String desc;
}
@Data
public class OrderDetail {
private Long id;
private Long orderId;
private Long money;
private Integer status;
}
@Data
public class Payment {
public void cancel() {
this.status = 1;
}
private Long id;
private Long money;
private Integer status;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderResp {
private Long id;
}
public class OrderDto {
private Long id;
private Long money;
private List<PaymentDto> paymentDtos;
}
public class PaymentDto {
private Long id;
private Long money;
private Integer status;
}
public class OrderDo {
private Long id;
private Long money;
private List<PaymentDo> paymentDos;
}
public class PaymentDo {
private Long id;
private Long money;
private Integer status;
}
public class OrderRepository {
OrderMapper orderMapper;
PaymentMapper paymentMapper;
OrderDetailMapper orderDetailMapper;
OrderFactory orderFactory;
private Order find(Long id) {
OrderPo order = orderMapper.find(id);
List<PaymentPo> payments = paymentMapper.listByOrderId(id);
return orderFactory.buildFromPo(order, payments);
}
private Order findByNo(String orderNo) {
OrderPo orderPo = orderMapper.find(orderNo);
List<PaymentPo> payments = paymentMapper.listByOrderId(orderPo.id);
return orderFactory.buildFromPo(orderPo, payments);
}
void update(Order order) {
orderMapper.update(null);
}
void updatePayment(Payment payment) {
paymentMapper.updatePayemnt(null);
}
Long addOrder(Order order) {
return orderMapper.insert(null);
}
Long addOrderDetail(OrderDetail orderDetail) {
return orderDetailMapper.insert(orderDetail);
}
}
public class OrderFactory {
private OrderRepository orderRepository;
public Order buildFromDo(OrderDo orderDo) {
Order order = BeanUtils.trans(orderDo, Order.class);
order.setOrderRepository(orderRepository);
return order;
}
public Order buildFromPo(OrderPo orderPo, List<PaymentPo> paymentPos) {
Order order = BeanUtils.trans(orderPo, Order.class);
order.setOrderRepository(orderRepository);
order.payments = paymentPos.stream().map(x -> {
Payment payment = BeanUtils.trans(null, Payment.class);
return payment;
}).collect(Collectors.toList());
return order;
}
}
@Getter
@AllArgsConstructor
public enum EventType {
PLACE(1, "下单"),
CANCEL(2, "撤销"),
UPDATE(3, "修改订单");
private int code;
private String desc;
}
@Data
@AllArgsConstructor
public class OrderEvent {
private int type;
private Object data;
}
public class OrderEventBus {
public void send(OrderEvent event) {
}
}
public interface PaymentMapper {
List<PaymentPo> listByOrderId(Long orderId);
int updatePayemnt(PaymentPo payment);
}
public interface OrderDetailMapper {
OrderPo find(Long id);
Long insert(OrderDetail orderDetail);
}
public interface OrderMapper {
OrderPo find(Long id);
OrderPo find(String no);
int update(OrderPo order);
Long insert(OrderPo order);
}
@Data
public class OrderPo {
public Long id;
public long money;
}
@Data
public class PaymentPo {
public Long id;
public int status;
public Long money;
}
网友评论