【微服务实战】01-工程结构概览

文章目录

工程结构概览:定义应用分层及依赖关系

1.应用分层

  • 领域模型层
  • 基础设施层 ⇒ 仓储
  • 应用层 ⇒ Api、后台任务Job
  • 共享层

总结

  • 领域模型专注业务的设计,不依赖仓储等基础设施层
  • 基础设施的仓储层仅负责领域模型的取出和存储
  • 使用CQRS模式设计应用层
  • Web Api是面向前端的交互的接口,避免依赖领域模型
  • 将共享代码设计为共享包,使用私有Nuget仓库分发管理

2.定义Entity

要点总结

  • 将领域模型字段的修改设置为私有
  • 使用构造函数表示对象的创建
  • 使用具有业务含义的动作来操作模型字段
  • 领域模型负责对自己数据的处理
  • 领域服务或命令处理者负责调用领域模型业务动作

3.仓储层

3.1 工作单元:事务管理

仓储层最重要的就是事务的管理,这里通过工作单元模式实现事务管理

工作单元特性

  • 使用同一上下文
  • 跟踪实体的状态
  • 保障事务一致性

3.2 仓储层

仓储层接口TEntity必须继承Entity,并且必须实现聚合根,也就是仓储中储存的对象是一个聚合根对象,

复制代码
public interface IRepository<TEntity>  where TEntity : Entity,IAggregateRoot
{
	IUnitOfWork UnitOfWork {get;}
	TEntity Add(TEntity entity);
	TEntity Update(TEntity entity);
}

public interface IRepository<TEntity,TKey>:IRepository<TEntity> where TEntity : Entity<TKey>,IAggregateRoot
{
	bool Delete(TKey id);
	TEntity Get(TKey id);
}

4.领域事件

  • 领域事件的构造和添加都应该在领域模型的方法内完成,不应该被外界的代码调用创建,因为这些事件都是领域模型内部发生的
  • 接受领域事件的处理应该定义在应用层
  • 创建完领域模型并保存之后,领域事件的处理程序才触发

总结

1.由领域模型内部创建事件

2.由专有的领域事件处理类处理领域事件

3.根据实际情况来决定是否在同一事务中处理(如一致性、性能等因素)

5.APIController最佳实践

复制代码
// 伪代码

[HttpGet]
public Task<long> CreateOrder([FromBody]CreateOrderViewModel viewModel)
{
	var model = viewModel.ToModel();// 模型转换
	return await orderService.CreateOrder(model);// 业务代码调用
}

// 服务中代码
class OrderService : IOrderService
{
	public long CreateOrder(CreateOrderMode model)
	{
		var address = new Address("测试路","测试市区","123");
		var order = new Order("订单名称","客户名称",999,address);
		_orderRepository.Add(order);
		await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
		return order.Id;
	}
}

上述代码,随着业务逻辑的复杂化,Controller就会越来越膨胀。而DD领域设计的理念中,更新倾向于把应用程序的每一层明确区分,层与层之间的界限应该是明确的,同时在实现上应该也是隔离的。因此控制器不应该负责处理领域模型,处理仓储这些动作,Controller应该负责与前端交互,主要责任应该是定义输入和输出,实现身份认证、授权等功能。因此上述代码不建议使用

推荐使用中间者模式,演示代码如下

复制代码
// 这里不建议使用属性服务进行服务注册,因为当使用属性注入的时候,需要把属性设置为public,并且开放set,get方法,可能出现意外情况,这可能导致代码的维护不可控
IMediator _mediator;
public OrderController(IMediator mediator)
{
	_mediator = mediator;
}

// 这里尽可能的定义异步的action,可以帮助提高应用程序的吞吐量
[HttpPost]
public async Task<long> CreateOrder([FromBody] CreateOrderCommans cmd)
{
	return await _mediator.Send(cmd,HttpContext.RequestAborted);
}

总结

  • 负责用户的输入输出定义
  • 负责身份认证和授权
  • 与领域服务职责区分开,不承载业务逻辑
相关推荐
计算机学姐9 小时前
基于SpringBoot的高校爱心慈善管理系统
java·vue.js·spring boot·后端·spring·tomcat·mybatis
vx+_bysj68699 小时前
springboot 旅行小程序97353
spring boot·后端·小程序·旅行小程序
山岚的运维笔记9 小时前
mysql 专业笔记 -- 第 14 章:GROUP BY
运维·数据库·笔记·后端·学习·mysql·dba
后台模板学习9 小时前
Rust vs Python 在用户认证模块中的实现:底层
开发语言·python·rust
凤城老人9 小时前
基于 Flask 的企业级 CMS 架构设计与实现
后端·python·flask
所念皆星海9119 小时前
Python学习---DAY10函数
开发语言·python·学习
天天喝旺仔9 小时前
gRPC 流式通信实战:从一元调用到双向流,吃透四种 RPC 模式(Go 版)
分布式·http·微服务·rpc·go
wuyk55511 小时前
104.C 语言字节对齐:从底层原理到工程实践的完整指南
c语言·开发语言·stm32·单片机·嵌入式硬件
君顾117 小时前
智慧零售实战指南:从技术架构到落地方案全解析
java·开发语言·零售
南棱笑笑生18 小时前
20260904实测给飞凌OK3576-C开发板刷入Rockchip原厂的IMG固件【使用飞凌的DTS】切换串口波特率为1.5Mbps
c语言·开发语言·rockchip