GitHub_Trending Project-Ideas:微服务架构项目解析
你还在单体架构的泥潭中挣扎吗?
当你的项目遇到这些困境:
- 代码库臃肿不堪,新功能开发周期越来越长
- 团队协作冲突不断,合并代码如同"拆弹"
- 单一故障点导致整个系统瘫痪
- 不同模块需要不同技术栈却无法实现
- 流量高峰时服务器资源浪费严重
本文将通过6个实战维度,带你系统掌握微服务架构设计与实现,从根本上解决以上问题。读完本文你将获得:
- 微服务架构核心设计原则与评估标准
- 服务拆分的6种实战模式与决策框架
- 分布式系统通信的5种方案与代码实现
- 服务治理全流程解决方案(注册/发现/熔断/限流)
- 3个企业级微服务项目模板(含代码)
- DevOps与容器化部署最佳实践
一、微服务架构基础:从理论到实践
1.1 微服务定义与演进
微服务(Microservices)是一种架构风格,它将应用程序构建为一系列小型、自治的服务,每个服务围绕特定业务能力构建,通过轻量级机制通信。
1.2 微服务与单体架构对比
| 特性 | 微服务架构 | 单体架构 |
|---|---|---|
| 代码组织 | 多个小型代码库 | 单一代码库 |
| 部署单元 | 独立部署 | 整体部署 |
| 技术栈 | 多样化选择 | 统一技术栈 |
| 扩展性 | 按需独立扩展 | 整体扩展 |
| 故障影响 | 局部影响 | 整体影响 |
| 开发效率 | 初期低,后期高 | 初期高,后期低 |
| 团队协作 | 自治团队,并行开发 | 集中式团队 |
| 学习曲线 | 陡峭 | 平缓 |
1.3 微服务成熟度评估矩阵
微服务就绪度评分表(满分100分):
| 评估维度 | 评分标准 | 权重 |
|---|---|---|
| 业务复杂度 | 领域边界清晰程度 | 30% |
| 团队结构 | 康威定律匹配度 | 25% |
| 技术能力 | 分布式系统经验 | 20% |
| 运维水平 | DevOps成熟度 | 15% |
| 业务增长 | 扩展需求迫切性 | 10% |
二、微服务架构设计核心原则
2.1 领域驱动设计(DDD)实践
核心概念映射:
| DDD概念 | 微服务实现 |
|---|---|
| 领域(Domain) | 业务域 |
| 限界上下文(Bounded Context) | 微服务边界 |
| 聚合(Aggregate) | 服务内部数据模型 |
| 领域事件(Domain Event) | 服务间通信事件 |
| 领域服务(Domain Service) | 微服务API |
事件风暴工作坊流程:
2.2 微服务拆分策略与模式
六种拆分模式对比:
| 拆分模式 | 适用场景 | 优点 | 挑战 |
|---|---|---|---|
| 按业务能力拆分 | 业务边界清晰场景 | 符合业务演进 | 初期划分困难 |
| 按子域拆分 | 大型复杂业务系统 | 与DDD高度契合 | 需资深领域专家 |
| 按数据拆分 | 数据密集型应用 | 数据隔离性好 | 分布式事务复杂 |
| 按技术层次拆分 | 技术栈差异大的系统 | 技术自由度高 | 易形成分布式单体 |
| 按团队拆分 | 大型团队协作 | 符合康威定律 | 可能导致服务粒度不均 |
| 渐进式拆分 | 单体系统迁移 | 风险可控 | 需要过渡方案 |
拆分决策框架:
2.3 服务粒度设计指南
DORA指标与服务粒度关系:
| 服务数量区间 | 部署频率 | 变更失败率 | 恢复时间 | 适合团队规模 |
|---|---|---|---|---|
| 1-5个服务 | 每周1-2次 | <5% | <1小时 | 小型团队(1-5人) |
| 6-20个服务 | 每天1-2次 | 5-10% | 1-4小时 | 中型团队(6-20人) |
| 21-50个服务 | 每天多次 | 10-15% | 4-8小时 | 大型团队(21-50人) |
| 50+个服务 | 持续部署 | 15-20% | 8-24小时 | 超大型团队(50+人) |
服务粒度检查清单:
- 代码量:单个服务代码量控制在1-10万行
- 团队规模:"两个披萨团队"原则(5-9人)
- 部署频率:独立部署周期不超过2周
- 变更影响:变更影响范围不超过2个依赖服务
- 接口数量:对外API不超过20个核心接口
三、微服务通信模式与实现
3.1 同步通信机制
REST API设计最佳实践:
// 用户服务API示例(Node.js)
const express = require('express');
const app = express();
app.use(express.json());
// 资源命名使用复数名词
app.get('/users', async (req, res) => {
const { page = 1, limit = 20, status } = req.query;
// 实现分页和过滤逻辑
const users = await userService.find({
page,
limit,
status
});
// 返回HATEOAS链接
res.json({
data: users.items,
pagination: {
total: users.total,
page,
limit,
pages: Math.ceil(users.total / limit)
},
links: {
self: `${req.protocol}://${req.get('host')}${req.originalUrl}`,
next: users.hasMore ? `${req.protocol}://${req.get('host')}/users?page=${page+1}&limit=${limit}` : null
}
});
});
// 使用正确的HTTP方法和状态码
app.post('/users', (req, res) => {
// 验证请求
const validation = userValidator.validate(req.body);
if (!validation.isValid) {
return res.status(400).json({
error: 'VALIDATION_ERROR',
details: validation.errors
});
}
// 创建用户
const user = userService.create(req.body);
return res.status(201).json(user);
});
app.listen(3000);
GraphQL API实现(与微服务集成):
// 产品服务GraphQL模式定义
const typeDefs = gql`
type Product {
id: ID!
name: String!
price: Float!
stock: Int!
category: Category
reviews: [Review]
}
type Category {
id: ID!
name: String!
products: [Product]
}
type Query {
product(id: ID!): Product
products(category: ID, page: Int, limit: Int): ProductConnection
}
type ProductConnection {
edges: [ProductEdge]
pageInfo: PageInfo
}
type ProductEdge {
node: Product
cursor: String
}
type PageInfo {
hasNextPage: Boolean
endCursor: String
}
`;
// 解析器实现(集成其他微服务)
const resolvers = {
Product: {
// 跨服务获取评论数据
async reviews(product) {
return await fetchFromService({
service: 'review-service',
query: `query Reviews($productId: ID!) {
reviews(productId: $productId) {
id
rating
comment
user {
id
name
}
}
}`,
variables: { productId: product.id }
});
}
},
Query: {
async product(_, { id }) {
return await productService.findById(id);
},
async products(_, { category, page = 1, limit = 20 }) {
return await productService.find({ category, page, limit });
}
}
};
3.2 异步通信与事件驱动架构
事件驱动架构组件:
Kafka实现事件通信:
// 订单服务 - 事件生产者
const { Kafka } = require('kafkajs');
const kafka = new Kafka({
clientId: 'order-service',
brokers: ['kafka-1:9092', 'kafka-2:9092'] // 使用Kafka集群
});
const producer = kafka.producer();
async function initProducer() {
await producer.connect();
}
// 发布订单创建事件
async function publishOrderCreated(order) {
try {
await producer.send({
topic: 'order-events',
messages: [
{
key: order.id,
value: JSON.stringify({
type: 'ORDER_CREATED',
payload: order,
metadata: {
timestamp: new Date().toISOString(),
service: 'order-service',
version: '1.0.0'
}
}),
headers: {
eventType: 'ORDER_CREATED',
correlationId: order.correlationId
}
}
]
});
console.log(`Order event published: ${order.id}`);
} catch (error) {
console.error('Failed to publish event:', error);
// 实现重试机制或发送到死信队列
await handleEventPublishFailure(error, order);
}
}
// 库存服务 - 事件消费者
const consumer = kafka.consumer({
groupId: 'inventory-service-group',
retry: {
initialRetryTime: 300,
maxRetryTime: 3000,
retries: 5
}
});
async function initConsumer() {
await consumer.connect();
await consumer.subscribe({
topic: 'order-events',
fromBeginning: false
});
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
try {
const event = JSON.parse(message.value.toString());
// 根据事件类型处理
switch (event.type) {
case 'ORDER_CREATED':
await handleOrderCreated(event.payload);
break;
case 'ORDER_CANCELLED':
await handleOrderCancelled(event.payload);
break;
default:
console.log(`Unknown event type: ${event.type}`);
}
} catch (error) {
console.error('Error processing message:', error);
// 根据错误类型决定是否抛出(触发重试)
if (isRetriableError(error)) {
throw error; // 触发Kafka重试
} else {
// 不可重试错误,记录并继续
await logToErrorQueue(message, error);
}
}
}
});
}
四、微服务架构核心组件实现
4.1 服务注册与发现
比较与选型:
| 服务发现方案 | 实现方式 | 一致性 | 可用性 | 适用场景 |
|---|---|---|---|---|
| Eureka | AP架构 | 最终一致 | 高可用 | AWS/云环境 |
| Consul | CP架构 | 强一致 | 一般 | 对一致性要求高的环境 |
| etcd | CP架构 | 强一致 | 较高 | Kubernetes环境 |
| ZooKeeper | CP架构 | 强一致 | 一般 | 复杂分布式协调 |
| Nacos | 可配置AP/CP | 可切换 | 高 | 混合部署环境 |
Spring Cloud服务注册发现实现:
// 服务提供者配置(application.yml)
spring:
application:
name: order-service
eureka:
client:
serviceUrl:
defaultZone: http://eureka-server-1:8761/eureka/,http://eureka-server-2:8762/eureka/
instance:
preferIpAddress: true
lease-renewal-interval-in-seconds: 30 # 心跳间隔
lease-expiration-duration-in-seconds: 90 # 过期时间
// 服务提供者代码
@SpringBootApplication
@EnableEurekaClient
@RestController
public class OrderServiceApplication {
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable String id) {
// 实现订单查询逻辑
return orderService.findById(id);
}
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
// 服务消费者代码
@SpringBootApplication
@EnableEurekaClient
@RestController
public class PaymentServiceApplication {
@Autowired
private RestTemplate restTemplate;
@Bean
@LoadBalanced // 启用负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/payments/{id}/order")
public Order getPaymentOrder(@PathVariable String id) {
// 根据支付ID获取订单ID
String orderId = paymentService.getOrderId(id);
// 通过服务名调用,而非硬编码URL
return restTemplate.getForObject(
"http://order-service/orders/" + orderId,
Order.class
);
}
public static void main(String[] args) {
SpringApplication.run(PaymentServiceApplication.class, args);
}
}
4.2 API网关设计与实现
API网关核心功能:
Spring Cloud Gateway实现:
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 产品服务路由
.route("product-service", r -> r.path("/api/products/**")
.filters(f -> f
.rewritePath("/api/(?<segment>.*)", "/${segment}")
.addResponseHeader("X-Response-Time", "${responseTime}")
.requestRateLimiter(c -> c
.setRateLimiter(redisRateLimiter())
.setKeyResolver(userKeyResolver())
)
.circuitBreaker(c -> c
.setName("productServiceCircuitBreaker")
.setFallbackUri("forward:/fallback/products")
)
)
.uri("lb://product-service")) // 负载均衡到产品服务
// 用户服务路由
.route("user-service", r -> r.path("/api/users/**")
.filters(f -> f
.rewritePath("/api/(?<segment>.*)", "/${segment}")
.filter(authenticationFilter()) // 自定义认证过滤器
.retry(c -> c
.setRetries(3)
.setStatuses(HttpStatus.SERVICE_UNAVAILABLE)
)
)
.uri("lb://user-service"))
// 订单服务路由
.route("order-service", r -> r.path("/api/orders/**")
.filters(f -> f
.rewritePath("/api/(?<segment>.*)", "/${segment}")
.addRequestHeader("X-Request-ID", "${randomUUID}")
.requestSize(c -> c.setMaxSize(1000000)) // 请求大小限制
)
.uri("lb://order-service"))
.build();
}
@Bean
public RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(10, 20); // 令牌桶限流:稳定10r/s,突发20r/s
}
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
Optional.ofNullable(exchange.getRequest().getHeaders().getFirst("X-User-ID"))
.orElse(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress())
);
}
}
4.3 服务容错与弹性设计
熔断降级实现:
// 使用Resilience4j实现熔断降级(Node.js)
const { CircuitBreaker, TimeLimiter, Retry } = require('@resilience4j/circuitbreaker');
const { promisify } = require('util');
// 配置熔断器
const circuitBreaker = new CircuitBreaker({
failureRateThreshold: 50, // 失败率阈值,超过则打开熔断器
waitDurationInOpenState: 10000, // 熔断器打开状态持续时间(ms)
slidingWindowSize: 10, // 滑动窗口大小
minimumNumberOfCalls: 5, // 最小调用次数
permittedNumberOfCallsInHalfOpenState: 3 // 半开状态允许的调用次数
});
// 配置超时限制
const timeLimiter = new TimeLimiter({
timeoutDuration: 3000 // 超时时间(ms)
});
// 配置重试策略
const retry = new Retry({
maxRetryAttempts: 3, // 最大重试次数
waitDuration: 1000, // 重试间隔(ms)
retryExceptions: [TimeoutError, NetworkError], // 需要重试的异常类型
ignoreExceptions: [ValidationError] // 忽略的异常类型
});
// 包装远程服务调用
async function callPaymentService(paymentDetails) {
// 创建带超时限制的函数
const timeLimitedFn = timeLimiter.wrap(() =>
fetch('http://payment-service/api/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paymentDetails)
})
.then(response => {
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
return response.json();
})
);
// 创建带重试机制的函数
const retryableFn = retry.wrap(timeLimitedFn);
// 创建带熔断机制的函数
const circuitBreakerFn = circuitBreaker.wrap(retryableFn);
try {
return await circuitBreakerFn();
} catch (error) {
// 处理最终异常或熔断器打开状态
if (error instanceof CircuitBreakerOpenError) {
console.log('Payment service circuit is open, using fallback');
// 调用降级方案
return processWithFallbackPayment(paymentDetails);
}
throw error;
}
}
// 降级方案实现
async function processWithFallbackPayment(paymentDetails) {
// 实现降级逻辑,如使用备用支付服务或队列
return await fallbackPaymentQueue.enqueue(paymentDetails);
}
舱壁模式实现:
// 使用线程池隔离实现舱壁模式(Java)
@Configuration
public class ThreadPoolConfig {
// 订单服务线程池
@Bean(name = "orderServiceExecutor")
public Executor orderServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(10); // 最大线程数
executor.setQueueCapacity(20); // 队列容量
executor.setThreadNamePrefix("order-service-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
// 支付服务线程池
@Bean(name = "paymentServiceExecutor")
public Executor paymentServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(6);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("payment-service-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
// 库存服务线程池
@Bean(name = "inventoryServiceExecutor")
public Executor inventoryServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(15);
executor.setThreadNamePrefix("inventory-service-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
// 使用舱壁模式调用外部服务
@Service
public class OrderProcessingService {
private final RestTemplate restTemplate;
@Autowired
public OrderProcessingService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// 使用订单服务线程池
@Async("orderServiceExecutor")
public CompletableFuture<OrderResponse> processOrder(OrderRequest request) {
// 处理订单逻辑
return CompletableFuture.completedFuture(new OrderResponse(request.getId()));
}
// 使用支付服务线程池
@Async("paymentServiceExecutor")
public CompletableFuture<PaymentResponse> processPayment(PaymentRequest request) {
try {
return CompletableFuture.supplyAsync(() ->
restTemplate.postForObject(
"http://payment-service/api/payments",
request,
PaymentResponse.class
)
);
} catch (Exception e) {
throw new ServiceException("Payment service error", e);
}
}
// 使用库存服务线程池
@Async("inventoryServiceExecutor")
public CompletableFuture<InventoryResponse> checkInventory(InventoryRequest request) {
try {
return CompletableFuture.supplyAsync(() ->
restTemplate.postForObject(
"http://inventory-service/api/inventory/check",
request,
InventoryResponse.class
)
);
} catch (Exception e) {
throw new ServiceException("Inventory service error", e);
}
}
}
五、微服务数据管理
5.1 分布式事务解决方案
事务模式对比:
| 事务模式 | 一致性 | 可用性 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| 2PC/3PC | 强一致 | 低 | 高 | 短事务、关键业务 |
| SAGA | 最终一致 | 高 | 中 | 长事务、跨多服务 |
| TCC | 最终一致 | 高 | 高 | 核心业务、高性能需求 |
| 本地消息表 | 最终一致 | 高 | 低 | 非实时、低复杂度 |
| 事务消息 | 最终一致 | 中 | 中 | 异步通信场景 |
SAGA模式实现:
// 订单SAGA编排器(Node.js)
class OrderSagaOrchestrator {
constructor(orderService, paymentService, inventoryService, shippingService) {
this.orderService = orderService;
this.paymentService = paymentService;
this.inventoryService = inventoryService;
this.shippingService = shippingService;
this.sagaRepository = new SagaRepository();
}
// 启动订单SAGA
async startOrderSaga(orderData) {
// 创建SAGA实例并记录状态
const sagaId = uuidv4();
await this.sagaRepository.createSaga({
id: sagaId,
type: 'ORDER_PROCESSING',
status: 'STARTED',
data: orderData,
steps: []
});
try {
// 步骤1: 创建订单
const order = await this.createOrder(sagaId, orderData);
// 步骤2: 扣减库存
const inventoryResult = await this.reserveInventory(sagaId, order.id, order.items);
// 步骤3: 处理支付
const paymentResult = await this.processPayment(sagaId, order.id, orderData.payment);
// 步骤4: 创建物流单
const shippingResult = await this.createShipment(sagaId, order.id, orderData.shipping);
// 完成SAGA
await this.sagaRepository.updateSagaStatus(sagaId, 'COMPLETED');
return { success: true, orderId: order.id };
} catch (error) {
console.error('SAGA failed, initiating compensating transactions', error);
await this.compensateSaga(sagaId, error);
throw error;
}
}
async createOrder(sagaId, orderData) {
const stepId = this._generateStepId('CREATE_ORDER');
await this.sagaRepository.addSagaStep(sagaId, {
id: stepId,
action: 'CREATE_ORDER',
status: 'EXECUTING'
});
try {
const order = await this.orderService.createOrder(orderData);
await this.sagaRepository.updateSagaStep(sagaId, stepId, {
status: 'COMPLETED',
result: { orderId: order.id }
});
return order;
} catch (error) {
await this.sagaRepository.updateSagaStep(sagaId, stepId, {
status: 'FAILED',
error: error.message
});
throw error;
}
}
async reserveInventory(sagaId, orderId, items) {
const stepId = this._generateStepId('RESERVE_INVENTORY');
await this.sagaRepository.addSagaStep(sagaId, {
id: stepId,
action: 'RESERVE_INVENTORY',
status: 'EXECUTING'
});
try {
const result = await this.inventoryService.reserveItems({
orderId,
items: items.map(item => ({
productId: item.productId,
quantity: item.quantity
}))
});
await this.sagaRepository.updateSagaStep(sagaId, stepId, {
status: 'COMPLETED',
result,
compensationAction: 'RELEASE_INVENTORY',
compensationData: { reservationId: result.reservationId }
});
return result;
} catch (error) {
await this.sagaRepository.updateSagaStep(sagaId, stepId, {
status: 'FAILED',
error: error.message
});
throw error;
}
}
// 其他步骤实现...
// 补偿事务
async compensateSaga(sagaId, error) {
await this.sagaRepository.updateSagaStatus(sagaId, 'COMPENSATING');
// 获取已完成的步骤,按逆序执行补偿
const saga = await this.sagaRepository.getSaga(sagaId);
const completedSteps = saga.steps
.filter(step => step.status === 'COMPLETED' && step.compensationAction)
.reverse();
for (const step of completedSteps) {
try {
console.log(`Compensating step ${step.action} for saga ${sagaId}`);
switch (step.compensationAction) {
case 'RELEASE_INVENTORY':
await this.inventoryService.releaseReservation(step.compensationData.reservationId);
break;
case 'REFUND_PAYMENT':
await this.paymentService.refundPayment(step.compensationData.paymentId);
break;
case 'CANCEL_SHIPMENT':
await this.shippingService.cancelShipment(step.compensationData.shipmentId);
break;
case 'DELETE_ORDER':
await this.orderService.deleteOrder(step.compensationData.orderId);
break;
}
await this.sagaRepository.updateSagaStep(sagaId, step.id, {
compensationStatus: 'COMPLETED'
});
} catch (compensationError) {
console.error(`Compensation failed for step ${step.id}:`, compensationError);
await this.sagaRepository.updateSagaStep(sagaId, step.id, {
compensationStatus: 'FAILED',
compensationError: compensationError.message
});
// 记录补偿失败,需要人工干预
await this.notifyAdminForManualIntervention(sagaId, step, compensationError);
}
}
await this.sagaRepository.updateSagaStatus(sagaId, 'COMPENSATED');
}
// 辅助方法...
}
5.2 CQRS模式实践
CQRS架构实现:
// C#实现CQRS架构
// 1. 命令定义
public class CreateProductCommand : ICommand<Guid>
{
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
public string Category { get; set; }
}
// 2. 命令处理器
public class CreateProductCommandHandler : ICommandHandler<CreateProductCommand, Guid>
{
private readonly IProductRepository _repository;
private readonly IEventPublisher _eventPublisher;
public CreateProductCommandHandler(IProductRepository repository, IEventPublisher eventPublisher)
{
_repository = repository;
_eventPublisher = eventPublisher;
}
public async Task<Guid> Handle(CreateProductCommand command, CancellationToken cancellationToken)
{
// 领域逻辑验证
if (command.Price <= 0)
throw new ArgumentException("Product price must be greater than zero");
// 创建领域实体
var product = new Product(
Guid.NewGuid(),
command.Name,
command.Price,
command.Stock,
command.Category
);
// 保存实体
await _repository.AddAsync(product);
// 发布领域事件
await _eventPublisher.Publish(new ProductCreatedEvent
{
ProductId = product.Id,
Name = product.Name,
Price = product.Price,
Category = product.Category,
Timestamp = DateTime.UtcNow
});
return product.Id;
}
}
// 3. 查询定义
public class GetProductByIdQuery : IQuery<ProductDetailDto>
{
public Guid ProductId { get; set; }
}
// 4. 查询处理器
public class GetProductByIdQueryHandler : IQueryHandler<GetProductByIdQuery, ProductDetailDto>
{
private readonly IReadDbContext _readDbContext;
public GetProductByIdQueryHandler(IReadDbContext readDbContext)
{
_readDbContext = readDbContext;
}
public async Task<ProductDetailDto> Handle(GetProductByIdQuery query, CancellationToken cancellationToken)
{
// 从只读数据库查询数据
var product = await _readDbContext.Products
.Where(p => p.Id == query.ProductId)
.Select(p => new ProductDetailDto
{
Id = p.Id,
Name = p.Name,
Price = p.Price,
Stock = p.Stock,
Category = p.Category,
CreatedAt = p.CreatedAt,
LastUpdated = p.LastUpdated
})
.FirstOrDefaultAsync(cancellationToken);
if (product == null)
throw new NotFoundException($"Product with ID {query.ProductId} not found");
return product;
}
}
// 5. 事件处理器(更新读模型)
public class ProductCreatedEventHandler : IEventHandler<ProductCreatedEvent>
{
private readonly IReadDbContext _readDbContext;
public ProductCreatedEventHandler(IReadDbContext readDbContext)
{
_readDbContext = readDbContext;
}
public async Task Handle(ProductCreatedEvent @event, CancellationToken cancellationToken)
{
// 更新读模型
var productReadModel = new ProductReadModel
{
Id = @event.ProductId,
Name = @event.Name,
Price = @event.Price,
Stock = @event.Stock,
Category = @event.Category,
CreatedAt = @event.Timestamp,
LastUpdated = @event.Timestamp
};
_readDbContext.Products.Add(productReadModel);
await _readDbContext.SaveChangesAsync(cancellationToken);
}
}
// 6. API控制器
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



