前言

在前面的七篇文章中,我们从零开始构建了一个功能完整的 HTTP 客户端框架。理论知识固然重要,但实际应用才是检验框架价值的试金石。本文将通过三个不同复杂度的实战案例,展示如何在真实项目中使用 Atlas HTTP Client 框架。

这三个案例分别是:

  1. 基础案例:用户管理系统 - 展示基本的 CRUD 操作
  2. 进阶案例:电商订单系统 - 展示复杂业务场景和异步处理
  3. 高级案例:微服务网关 - 展示高性能和高可用架构

每个案例都会包含完整的代码实现、配置说明和最佳实践建议。

案例一:用户管理系统(基础案例)

业务场景

这是一个典型的用户管理系统,需要与后端 API 进行交互,实现用户的增删改查功能。这个案例展示了框架的基本使用方法。

项目结构

user-management-demo/
├── src/main/java/
│   ├── com/example/user/
│   │   ├── UserManagementApplication.java
│   │   ├── client/
│   │   │   └── UserApiClient.java
│   │   ├── controller/
│   │   │   └── UserController.java
│   │   ├── service/
│   │   │   └── UserService.java
│   │   ├── model/
│   │   │   ├── User.java
│   │   │   ├── CreateUserRequest.java
│   │   │   └── UpdateUserRequest.java
│   │   └── config/
│   │       └── HttpClientConfig.java
│   └── resources/
│       └── application.yml
└── pom.xml

1. 依赖配置

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>io.github.nemoob</groupId>
        <artifactId>atlas-httpclient-spring-boot-starter</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
</dependencies>

2. 配置文件

# application.yml
server:
  port: 8080

atlas:
  httpclient:
    enabled: true
    default-connect-timeout: 5000
    default-read-timeout: 10000
    logging-enabled: true
    metrics-enabled: true
    
    # 拦截器配置
    interceptors:
      logging:
        log-headers: true
        log-body: true
        max-body-length: 1024
      retry:
        enabled: true
        max-retries: 3
        retry-delay: 1000

# 外部 API 配置
api:
  user-service:
    base-url: https://jsonplaceholder.typicode.com
    auth-token: your-api-token-here

3. 数据模型

// User.java
package com.example.user.model;

import com.fasterxml.jackson.annotation.JsonProperty;

public class User {
    private Long id;
    private String name;
    private String username;
    private String email;
    private String phone;
    private String website;
    private Address address;
    private Company company;
    
    // 构造函数
    public User() {}
    
    public User(String name, String username, String email) {
        this.name = name;
        this.username = username;
        this.email = email;
    }

### 6. 配置类

```java
// HttpClientConfig.java
package com.example.order.config;

import io.github.nemoob.httpclient.spring.annotation.EnableAtlasHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Configuration
@EnableAtlasHttpClient(basePackages = "com.example.order.client")
@EnableAsync
public class HttpClientConfig {
    
    @Bean("batchExecutor")
    public ExecutorService batchExecutor() {
        return Executors.newFixedThreadPool(20, r -> {
            Thread thread = new Thread(r, "batch-");
            thread.setDaemon(true);
            return thread;
        });
    }
    
    @Bean("notificationExecutor")
    public ExecutorService notificationExecutor() {
        return Executors.newCachedThreadPool(r -> {
            Thread thread = new Thread(r, "notification-");
            thread.setDaemon(true);
            return thread;
        });
    }
}

案例二总结

这个进阶案例展示了:

  1. 微服务协调:多个服务间的复杂交互和编排
  2. 异步处理:大量使用异步调用提高性能
  3. 高级拦截器:熔断器、限流器、分布式追踪
  4. 错误处理:完善的异常处理和回滚机制
  5. 事务管理:分布式事务的处理
  6. 性能优化:批量处理、并行执行

最佳实践

  • 使用熔断器防止服务雪崩
  • 实现限流保护服务稳定性
  • 添加分布式追踪便于问题排查
  • 设计完善的补偿机制
  • 合理使用异步处理提高吞吐量

案例三:微服务网关(高级案例)

业务场景

这是一个高性能的微服务网关,需要处理大量的并发请求,提供路由、负载均衡、认证、限流、监控等功能。这个案例展示了框架在高并发、高可用场景下的应用。

系统架构

客户端请求
    ↓
网关 (Gateway)
├── 路由服务 (Routing)
├── 负载均衡 (Load Balancer)
├── 认证服务 (Authentication)
├── 限流服务 (Rate Limiting)
├── 监控服务 (Monitoring)
└── 后端服务 (Backend Services)
    ├── 用户服务
    ├── 订单服务
    ├── 商品服务
    └── 支付服务

项目结构

gateway-demo/
├── src/main/java/
│   ├── com/example/gateway/
│   │   ├── GatewayApplication.java
│   │   ├── controller/
│   │   │   └── GatewayController.java
│   │   ├── service/
│   │   │   ├── GatewayService.java
│   │   │   ├── RouteService.java
│   │   │   ├── LoadBalancerService.java
│   │   │   └── AuthenticationService.java
│   │   ├── client/
│   │   │   └── BackendServiceClient.java
│   │   ├── model/
│   │   │   ├── GatewayRequest.java
│   │   │   ├── GatewayResponse.java
│   │   │   └── RouteConfig.java
│   │   ├── interceptor/
│   │   │   ├── PerformanceInterceptor.java
│   │   │   ├── SecurityInterceptor.java
│   │   │   └── MonitoringInterceptor.java
│   │   └── config/
│   │       ├── GatewayConfig.java
│   │       └── PerformanceConfig.java
│   └── resources/
│       └── application.yml
└── pom.xml

1. 配置文件

# application.yml
server:
  port: 8080
  tomcat:
    threads:
      max: 1000
      min-spare: 100
    max-connections: 10000
    accept-count: 1000

atlas:
  httpclient:
    enabled: true
    default-connect-timeout: 1000
    default-read-timeout: 3000
    logging-enabled: false  # 网关场景下关闭详细日志
    metrics-enabled: true
    
    # 高性能配置
    interceptors:
      retry:
        enabled: false  # 网关层不重试,由客户端决定

# 网关配置
gateway:
  routes:
    - id: user-service
      path: /api/users/**
      url: http://user-service:8080
      load-balancer:
        type: round-robin
        health-check: true
    - id: order-service
      path: /api/orders/**
      url: http://order-service:8081
      load-balancer:
        type: weighted
        weights: [70, 30]  # 权重分配
    - id: product-service
      path: /api/products/**
      url: http://product-service:8082
      load-balancer:
        type: least-connections
  
  # 限流配置
  rate-limit:
    global:
      requests-per-second: 10000
      burst-capacity: 20000
    per-client:
      requests-per-second: 100
      burst-capacity: 200
  
  # 认证配置
  auth:
    enabled: true
    jwt-secret: your-jwt-secret-key
    token-expiry: 3600
    excluded-paths:
      - /api/auth/login
      - /api/health
      - /actuator/**
  
  # 监控配置
  monitoring:
    metrics-enabled: true
    tracing-enabled: true
    slow-request-threshold: 1000  # 慢请求阈值(毫秒)

# 性能调优
spring:
  task:
    execution:
      pool:
        core-size: 50
        max-size: 500
        queue-capacity: 1000

2. 数据模型

// GatewayRequest.java
package com.example.gateway.model;

import java.util.Map;

public class GatewayRequest {
    private String path;
    private String method;
    private Map<String, String> headers;
    private Map<String, String> queryParams;
    private String body;
    private String clientIp;
    private String userId;
    private long timestamp;
    
    // 构造函数和 Getter/Setter 方法省略...
}

// GatewayResponse.java
package com.example.gateway.model;

import java.util.Map;

public class GatewayResponse {
    private int statusCode;
    private Map<String, String> headers;
    private String body;
    private long processingTime;
    private String errorMessage;
    
    // 构造函数和 Getter/Setter 方法省略...
}

// RouteConfig.java
package com.example.gateway.model;

import java.util.List;

public class RouteConfig {
    private String id;
    private String path;
    private String url;
    private LoadBalancerConfig loadBalancer;
    private boolean authRequired = true;
    private RateLimitConfig rateLimit;
    
    // 内部类
    public static class LoadBalancerConfig {
        private String type; // round-robin, weighted, least-connections
        private boolean healthCheck = true;
        private List<Integer> weights;
        private int healthCheckInterval = 30; // 秒
        
        // Getter/Setter 方法省略...
    }
    
    public static class RateLimitConfig {
        private int requestsPerSecond;
        private int burstCapacity;
        
        // Getter/Setter 方法省略...
    }
    
    // Getter/Setter 方法省略...
}

3. 高性能后端服务客户端

// BackendServiceClient.java
package com.example.gateway.client;

import io.github.nemoob.httpclient.annotation.*;

import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 通用后端服务客户端
 * 支持动态路由到不同的后端服务
 */
@HttpClient  // 不设置固定URL,运行时动态指定
@Interceptor({PerformanceInterceptor.class, MonitoringInterceptor.class})
public interface BackendServiceClient {
    
    /**
     * 通用GET请求
     */
    @GET("{path}")
    @Async(executor = "gatewayExecutor", timeout = 3000)
    CompletableFuture<String> get(
        @Path("path") String path,
        @Header("Host") String host,
        @Header Map<String, String> headers
    );
    
    /**
     * 通用POST请求
     */
    @POST("{path}")
    @Async(executor = "gatewayExecutor", timeout = 5000)
    CompletableFuture<String> post(
        @Path("path") String path,
        @Header("Host") String host,
        @Header Map<String, String> headers,
        @Body String body
    );
    
    /**
     * 通用PUT请求
     */
    @PUT("{path}")
    @Async(executor = "gatewayExecutor", timeout = 5000)
    CompletableFuture<String> put(
        @Path("path") String path,
        @Header("Host") String host,
        @Header Map<String, String> headers,
        @Body String body
    );
    
    /**
     * 通用DELETE请求
     */
    @DELETE("{path}")
    @Async(executor = "gatewayExecutor", timeout = 3000)
    CompletableFuture<String> delete(
        @Path("path") String path,
        @Header("Host") String host,
        @Header Map<String, String> headers
    );
    
    /**
     * 健康检查
     */
    @GET("/health")
    @Async(executor = "healthCheckExecutor", timeout = 1000)
    CompletableFuture<String> healthCheck(@Header("Host") String host);
}

4. 网关核心服务

// GatewayService.java
package com.example.gateway.service;

import com.example.gateway.client.BackendServiceClient;
import com.example.gateway.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 网关核心服务
 * 处理请求路由和转发
 */
@Service
public class GatewayService {
    
    @Autowired
    private BackendServiceClient backendServiceClient;
    
    @Autowired
    private RouteService routeService;
    
    @Autowired
    private LoadBalancerService loadBalancerService;
    
    @Autowired
    private AuthenticationService authenticationService;
    
    /**
     * 处理网关请求
     */
    public CompletableFuture<GatewayResponse> handleRequest(GatewayRequest request) {
        long startTime = System.currentTimeMillis();
        
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 1. 路由匹配
                RouteConfig route = routeService.findRoute(request.getPath());
                if (route == null) {
                    return createErrorResponse(404, "Route not found", startTime);
                }
                
                // 2. 认证检查
                if (route.isAuthRequired() && !authenticationService.authenticate(request)) {
                    return createErrorResponse(401, "Authentication failed", startTime);
                }
                
                // 3. 负载均衡
                String targetUrl = loadBalancerService.selectServer(route);
                if (targetUrl == null) {
                    return createErrorResponse(503, "No available servers", startTime);
                }
                
                // 4. 转发请求
                return forwardRequest(request, targetUrl, startTime).join();
                
            } catch (Exception e) {
                return createErrorResponse(500, "Internal server error: " + e.getMessage(), startTime);
            }
        });
    }
    
    /**
     * 转发请求到后端服务
     */
    private CompletableFuture<GatewayResponse> forwardRequest(GatewayRequest request, String targetUrl, long startTime) {
        // 构建请求头
        Map<String, String> headers = request.getHeaders();
        headers.put("X-Forwarded-For", request.getClientIp());
        headers.put("X-Gateway-Request-Id", generateRequestId());
        
        CompletableFuture<String> responseFuture;
        
        // 根据HTTP方法转发请求
        switch (request.getMethod().toUpperCase()) {
            case "GET":
                responseFuture = backendServiceClient.get(request.getPath(), targetUrl, headers);
                break;
            case "POST":
                responseFuture = backendServiceClient.post(request.getPath(), targetUrl, headers, request.getBody());
                break;
            case "PUT":
                responseFuture = backendServiceClient.put(request.getPath(), targetUrl, headers, request.getBody());
                break;
            case "DELETE":
                responseFuture = backendServiceClient.delete(request.getPath(), targetUrl, headers);
                break;
            default:
                return CompletableFuture.completedFuture(createErrorResponse(405, "Method not allowed", startTime));
        }
        
        return responseFuture
            .thenApply(responseBody -> {
                GatewayResponse response = new GatewayResponse();
                response.setStatusCode(200);
                response.setBody(responseBody);
                response.setProcessingTime(System.currentTimeMillis() - startTime);
                return response;
            })
            .exceptionally(throwable -> {
                return createErrorResponse(502, "Backend service error: " + throwable.getMessage(), startTime);
            });
    }
    
    /**
     * 创建错误响应
     */
    private GatewayResponse createErrorResponse(int statusCode, String errorMessage, long startTime) {
        GatewayResponse response = new GatewayResponse();
        response.setStatusCode(statusCode);
        response.setErrorMessage(errorMessage);
        response.setBody("{"error": "" + errorMessage + ""}");
        response.setProcessingTime(System.currentTimeMillis() - startTime);
        return response;
    }
    
    /**
     * 生成请求ID
     */
    private String generateRequestId() {
        return "GW-" + System.currentTimeMillis() + "-" + Thread.currentThread().getId();
    }
}

5. 高性能拦截器

// PerformanceInterceptor.java
package com.example.gateway.interceptor;

import io.github.nemoob.httpclient.AbstractRequestInterceptor;
import io.github.nemoob.httpclient.RequestContext;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 高性能拦截器
 * 专为网关场景优化的性能监控
 */
@Component
public class PerformanceInterceptor extends AbstractRequestInterceptor {
    
    private final LongAdder totalRequests = new LongAdder();
    private final AtomicLong totalResponseTime = new AtomicLong();
    private final LongAdder errorCount = new LongAdder();
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        totalRequests.increment();
        context.setAttribute("startTime", System.nanoTime());
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        long startTime = (Long) context.getAttribute("startTime");
        long duration = System.nanoTime() - startTime;
        totalResponseTime.addAndGet(duration);
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        errorCount.increment();
    }
    
    /**
     * 获取性能统计
     */
    public PerformanceStats getStats() {
        long requests = totalRequests.sum();
        long totalTime = totalResponseTime.get();
        long errors = errorCount.sum();
        
        double avgResponseTime = requests > 0 ? (double) totalTime / requests / 1_000_000 : 0; // 转换为毫秒
        double errorRate = requests > 0 ? (double) errors / requests : 0;
        
        return new PerformanceStats(requests, avgResponseTime, errorRate);
    }
    
    public static class PerformanceStats {
        public final long totalRequests;
        public final double avgResponseTime;
        public final double errorRate;
        
        public PerformanceStats(long totalRequests, double avgResponseTime, double errorRate) {
            this.totalRequests = totalRequests;
            this.avgResponseTime = avgResponseTime;
            this.errorRate = errorRate;
        }
    }
}

案例三总结

这个高级案例展示了:

  1. 高并发处理:优化的线程池和连接配置
  2. 动态路由:灵活的路由匹配和负载均衡
  3. 性能监控:轻量级的性能统计和监控
  4. 安全认证:JWT 认证和权限控制
  5. 容错机制:熔断器、限流器等保护机制
  6. 可观测性:分布式追踪和监控指标

最佳实践

  • 关闭不必要的日志以提高性能
  • 使用异步处理提高吞吐量
  • 实现健康检查和故障转移
  • 合理配置线程池和连接池
  • 添加性能监控和告警

总结

通过这三个实战案例,我们展示了 Atlas HTTP Client 框架在不同场景下的应用:

案例对比

特性基础案例进阶案例高级案例
复杂度简单 CRUD微服务编排高并发网关
并发量中等极高
异步使用部分异步大量异步全异步
拦截器基础拦截器高级拦截器性能优化拦截器
错误处理简单异常处理分布式事务容错和降级
监控基础监控分布式追踪实时性能监控

关键学习点

  1. 渐进式学习:从简单到复杂,逐步掌握框架特性
  2. 实际应用:每个案例都来自真实的业务场景
  3. 性能优化:展示了不同场景下的性能优化技巧
  4. 最佳实践:总结了每个场景的最佳实践
  5. 扩展性:展示了框架的强大扩展能力

选择建议

  • 新手开发者:从案例一开始,掌握基本用法
  • 有经验开发者:重点关注案例二的微服务编排
  • 架构师:深入研究案例三的高性能设计

希望这些实战案例能够帮助你更好地理解和使用 Atlas HTTP Client 框架,在实际项目中发挥其最大价值!


public String getName() { return name; }
public void setName(String name) { this.name = name; }

public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }

public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }

public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }

public String getWebsite() { return website; }
public void setWebsite(String website) { this.website = website; }

public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }

public Company getCompany() { return company; }
public void setCompany(Company company) { this.company = company; }

// 内部类
public static class Address {
    private String street;
    private String suite;
    private String city;
    private String zipcode;
    private Geo geo;
    
    // Getter 和 Setter 方法省略...
    
    public static class Geo {
        private String lat;
        private String lng;
        
        // Getter 和 Setter 方法省略...
    }
}

public static class Company {
    private String name;
    private String catchPhrase;
    private String bs;
    
    // Getter 和 Setter 方法省略...
}

}

// CreateUserRequest.java package com.example.user.model;

import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank;

public class CreateUserRequest { @NotBlank(message = "姓名不能为空") private String name;

@NotBlank(message = "用户名不能为空")
private String username;

@Email(message = "邮箱格式不正确")
@NotBlank(message = "邮箱不能为空")
private String email;

private String phone;
private String website;

// 构造函数和 Getter/Setter 方法省略...

}

// UpdateUserRequest.java package com.example.user.model;

import javax.validation.constraints.Email;

public class UpdateUserRequest { private String name; private String username;

@Email(message = "邮箱格式不正确")
private String email;

private String phone;
private String website;

// 构造函数和 Getter/Setter 方法省略...

}


### 4. HTTP 客户端接口

```java
// UserApiClient.java
package com.example.user.client;

import com.example.user.model.User;
import com.example.user.model.CreateUserRequest;
import com.example.user.model.UpdateUserRequest;
import io.github.nemoob.httpclient.annotation.*;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 用户 API 客户端
 * 与外部用户服务进行交互
 */
@HttpClient("${api.user-service.base-url}")
@Interceptor({AuthInterceptor.class, LoggingInterceptor.class})
public interface UserApiClient {
    
    /**
     * 获取所有用户
     */
    @GET("/users")
    List<User> getAllUsers();
    
    /**
     * 根据 ID 获取用户
     */
    @GET("/users/{id}")
    User getUserById(@Path("id") Long id);
    
    /**
     * 根据用户名搜索用户
     */
    @GET("/users")
    List<User> searchUsersByUsername(@Query("username") String username);
    
    /**
     * 创建新用户
     */
    @POST("/users")
    @Header("Content-Type: application/json")
    User createUser(@Body CreateUserRequest request);
    
    /**
     * 更新用户信息
     */
    @PUT("/users/{id}")
    @Header("Content-Type: application/json")
    User updateUser(@Path("id") Long id, @Body UpdateUserRequest request);
    
    /**
     * 删除用户
     */
    @DELETE("/users/{id}")
    @MethodInterceptor(AuditInterceptor.class)
    void deleteUser(@Path("id") Long id);
    
    /**
     * 异步获取用户列表
     */
    @GET("/users")
    @Async(executor = "userServiceExecutor")
    CompletableFuture<List<User>> getAllUsersAsync();
    
    /**
     * 批量获取用户信息
     */
    @GET("/users")
    @Async(executor = "batchExecutor")
    CompletableFuture<List<User>> getUsersByIds(@Query("ids") List<Long> ids);
}

5. 自定义拦截器

// AuthInterceptor.java
package com.example.user.interceptor;

import io.github.nemoob.httpclient.AbstractRequestInterceptor;
import io.github.nemoob.httpclient.RequestContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 认证拦截器
 * 自动为请求添加认证令牌
 */
@Component
public class AuthInterceptor extends AbstractRequestInterceptor {
    
    @Value("${api.user-service.auth-token}")
    private String authToken;
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        if (context.getRequest() != null && authToken != null && !authToken.isEmpty()) {
            context.getRequest().getHeaders().put("Authorization", "Bearer " + authToken);
        }
    }
}

// AuditInterceptor.java
package com.example.user.interceptor;

import io.github.nemoob.httpclient.AbstractRequestInterceptor;
import io.github.nemoob.httpclient.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 审计拦截器
 * 记录敏感操作的审计日志
 */
@Component
public class AuditInterceptor extends AbstractRequestInterceptor {
    
    private static final Logger auditLogger = LoggerFactory.getLogger("AUDIT");
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        String method = context.getRequest().getMethod().name();
        String url = context.getRequest().getUrl();
        
        auditLogger.info("审计日志 - 操作开始: {} {}", method, url);
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        String method = context.getRequest().getMethod().name();
        String url = context.getRequest().getUrl();
        long duration = context.getEndTime() - context.getStartTime();
        
        auditLogger.info("审计日志 - 操作完成: {} {} (耗时: {}ms)", method, url, duration);
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        String method = context.getRequest().getMethod().name();
        String url = context.getRequest().getUrl();
        
        auditLogger.error("审计日志 - 操作失败: {} {} - 错误: {}", method, url, ex.getMessage());
    }
}

6. 业务服务层

// UserService.java
package com.example.user.service;

import com.example.user.client.UserApiClient;
import com.example.user.model.User;
import com.example.user.model.CreateUserRequest;
import com.example.user.model.UpdateUserRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 用户业务服务
 * 封装用户相关的业务逻辑
 */
@Service
public class UserService {
    
    @Autowired
    private UserApiClient userApiClient;
    
    /**
     * 获取所有用户(带缓存)
     */
    @Cacheable(value = "users", key = "'all'")
    public List<User> getAllUsers() {
        return userApiClient.getAllUsers();
    }
    
    /**
     * 根据 ID 获取用户(带缓存)
     */
    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("用户 ID 不能为空或小于等于 0");
        }
        
        User user = userApiClient.getUserById(id);
        if (user == null) {
            throw new RuntimeException("用户不存在: " + id);
        }
        
        return user;
    }
    
    /**
     * 搜索用户
     */
    public List<User> searchUsers(String username) {
        if (username == null || username.trim().isEmpty()) {
            return getAllUsers();
        }
        
        return userApiClient.searchUsersByUsername(username.trim());
    }
    
    /**
     * 创建用户
     */
    @CacheEvict(value = "users", allEntries = true)
    public User createUser(CreateUserRequest request) {
        validateCreateRequest(request);
        
        try {
            return userApiClient.createUser(request);
        } catch (Exception e) {
            throw new RuntimeException("创建用户失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 更新用户
     */
    @CacheEvict(value = "users", key = "#id")
    public User updateUser(Long id, UpdateUserRequest request) {
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("用户 ID 不能为空或小于等于 0");
        }
        
        // 先检查用户是否存在
        getUserById(id);
        
        try {
            return userApiClient.updateUser(id, request);
        } catch (Exception e) {
            throw new RuntimeException("更新用户失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 删除用户
     */
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("用户 ID 不能为空或小于等于 0");
        }
        
        // 先检查用户是否存在
        getUserById(id);
        
        try {
            userApiClient.deleteUser(id);
        } catch (Exception e) {
            throw new RuntimeException("删除用户失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 异步获取用户列表
     */
    public CompletableFuture<List<User>> getAllUsersAsync() {
        return userApiClient.getAllUsersAsync()
            .exceptionally(throwable -> {
                // 异步异常处理
                throw new RuntimeException("异步获取用户列表失败", throwable);
            });
    }
    
    /**
     * 批量获取用户
     */
    public CompletableFuture<List<User>> getUsersByIds(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return CompletableFuture.completedFuture(List.of());
        }
        
        return userApiClient.getUsersByIds(ids);
    }
    
    /**
     * 验证创建用户请求
     */
    private void validateCreateRequest(CreateUserRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("创建用户请求不能为空");
        }
        
        if (request.getName() == null || request.getName().trim().isEmpty()) {
            throw new IllegalArgumentException("用户姓名不能为空");
        }
        
        if (request.getUsername() == null || request.getUsername().trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        
        if (request.getEmail() == null || request.getEmail().trim().isEmpty()) {
            throw new IllegalArgumentException("邮箱不能为空");
        }
    }
}

7. 控制器层

// UserController.java
package com.example.user.controller;

import com.example.user.model.User;
import com.example.user.model.CreateUserRequest;
import com.example.user.model.UpdateUserRequest;
import com.example.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 用户控制器
 * 提供用户管理的 REST API
 */
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    @Autowired
    private UserService userService;
    
    /**
     * 获取所有用户
     */
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers(
            @RequestParam(required = false) String username) {
        
        List<User> users;
        if (username != null && !username.trim().isEmpty()) {
            users = userService.searchUsers(username);
        } else {
            users = userService.getAllUsers();
        }
        
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据 ID 获取用户
     */
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(
            @PathVariable @Min(value = 1, message = "用户 ID 必须大于 0") Long id) {
        
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
    
    /**
     * 创建新用户
     */
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) {
        User user = userService.createUser(request);
        return ResponseEntity.ok(user);
    }
    
    /**
     * 更新用户信息
     */
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(
            @PathVariable @Min(value = 1, message = "用户 ID 必须大于 0") Long id,
            @Valid @RequestBody UpdateUserRequest request) {
        
        User user = userService.updateUser(id, request);
        return ResponseEntity.ok(user);
    }
    
    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(
            @PathVariable @Min(value = 1, message = "用户 ID 必须大于 0") Long id) {
        
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
    
    /**
     * 异步获取用户列表
     */
    @GetMapping("/async")
    public CompletableFuture<ResponseEntity<List<User>>> getAllUsersAsync() {
        return userService.getAllUsersAsync()
            .thenApply(ResponseEntity::ok);
    }
    
    /**
     * 批量获取用户
     */
    @PostMapping("/batch")
    public CompletableFuture<ResponseEntity<List<User>>> getUsersByIds(
            @RequestBody List<Long> ids) {
        
        return userService.getUsersByIds(ids)
            .thenApply(ResponseEntity::ok);
    }
}

8. 配置类

// HttpClientConfig.java
package com.example.user.config;

import io.github.nemoob.httpclient.spring.annotation.EnableAtlasHttpClient;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * HTTP 客户端配置
 */
@Configuration
@EnableAtlasHttpClient(basePackages = "com.example.user.client")
@EnableCaching
@EnableAsync
public class HttpClientConfig {
    
    /**
     * 用户服务专用执行器
     */
    @Bean("userServiceExecutor")
    public ExecutorService userServiceExecutor() {
        return Executors.newFixedThreadPool(10, r -> {
            Thread thread = new Thread(r, "user-service-");
            thread.setDaemon(true);
            return thread;
        });
    }
    
    /**
     * 批量处理执行器
     */
    @Bean("batchExecutor")
    public ExecutorService batchExecutor() {
        return Executors.newCachedThreadPool(r -> {
            Thread thread = new Thread(r, "batch-");
            thread.setDaemon(true);
            return thread;
        });
    }
}

9. 启动类

// UserManagementApplication.java
package com.example.user;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserManagementApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserManagementApplication.class, args);
    }
}

10. 测试示例

// UserServiceTest.java
package com.example.user.service;

import com.example.user.client.UserApiClient;
import com.example.user.model.User;
import com.example.user.model.CreateUserRequest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@SpringBootTest
@SpringJUnitConfig
class UserServiceTest {
    
    @MockBean
    private UserApiClient userApiClient;
    
    @Autowired
    private UserService userService;
    
    @Test
    void testGetAllUsers() {
        // 准备测试数据
        List<User> mockUsers = Arrays.asList(
            new User("John Doe", "john", "[email protected]"),
            new User("Jane Smith", "jane", "[email protected]")
        );
        
        // 配置 Mock 行为
        when(userApiClient.getAllUsers()).thenReturn(mockUsers);
        
        // 执行测试
        List<User> result = userService.getAllUsers();
        
        // 验证结果
        assertNotNull(result);
        assertEquals(2, result.size());
        assertEquals("John Doe", result.get(0).getName());
        
        // 验证方法调用
        verify(userApiClient, times(1)).getAllUsers();
    }
    
    @Test
    void testCreateUser() {
        // 准备测试数据
        CreateUserRequest request = new CreateUserRequest();
        request.setName("Test User");
        request.setUsername("testuser");
        request.setEmail("[email protected]");
        
        User mockUser = new User("Test User", "testuser", "[email protected]");
        mockUser.setId(1L);
        
        // 配置 Mock 行为
        when(userApiClient.createUser(request)).thenReturn(mockUser);
        
        // 执行测试
        User result = userService.createUser(request);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(1L, result.getId());
        assertEquals("Test User", result.getName());
        
        // 验证方法调用
        verify(userApiClient, times(1)).createUser(request);
    }
}

案例一总结

这个基础案例展示了:

  1. 基本配置:如何配置 Atlas HTTP Client 和 Spring Boot 集成
  2. 接口定义:使用注解定义 HTTP 客户端接口
  3. 拦截器使用:认证和审计拦截器的实现
  4. 业务封装:在服务层封装业务逻辑和异常处理
  5. 缓存集成:与 Spring Cache 的集成使用
  6. 异步处理:异步方法的使用
  7. 测试方法:如何进行单元测试

最佳实践

  • 使用配置文件管理 API 地址和认证信息
  • 在服务层进行参数验证和异常处理
  • 合理使用缓存提高性能
  • 为敏感操作添加审计日志
  • 编写完整的单元测试

案例二:电商订单系统(进阶案例)

业务场景

这是一个电商订单系统,需要与多个微服务进行交互:用户服务、商品服务、库存服务、支付服务等。这个案例展示了复杂业务场景下的异步处理、事务管理和错误处理。

系统架构

订单服务 (Order Service)
├── 用户服务 (User Service)
├── 商品服务 (Product Service)
├── 库存服务 (Inventory Service)
├── 支付服务 (Payment Service)
└── 通知服务 (Notification Service)

项目结构

order-system-demo/
├── src/main/java/
│   ├── com/example/order/
│   │   ├── OrderSystemApplication.java
│   │   ├── client/
│   │   │   ├── UserServiceClient.java
│   │   │   ├── ProductServiceClient.java
│   │   │   ├── InventoryServiceClient.java
│   │   │   ├── PaymentServiceClient.java
│   │   │   └── NotificationServiceClient.java
│   │   ├── service/
│   │   │   ├── OrderService.java
│   │   │   └── OrderOrchestrationService.java
│   │   ├── model/
│   │   │   ├── Order.java
│   │   │   ├── OrderItem.java
│   │   │   ├── CreateOrderRequest.java
│   │   │   └── dto/
│   │   ├── interceptor/
│   │   │   ├── CircuitBreakerInterceptor.java
│   │   │   ├── RateLimitInterceptor.java
│   │   │   └── DistributedTracingInterceptor.java
│   │   └── config/
│   │       ├── HttpClientConfig.java
│   │       └── ResilienceConfig.java
│   └── resources/
│       └── application.yml
└── pom.xml

1. 配置文件

# application.yml
server:
  port: 8081

atlas:
  httpclient:
    enabled: true
    default-connect-timeout: 3000
    default-read-timeout: 5000
    logging-enabled: true
    metrics-enabled: true
    
    # 客户端特定配置
    clients:
      userService:
        base-url: http://user-service:8080
        connect-timeout: 2000
        read-timeout: 3000
      productService:
        base-url: http://product-service:8080
        connect-timeout: 2000
        read-timeout: 4000
      inventoryService:
        base-url: http://inventory-service:8080
        connect-timeout: 1000
        read-timeout: 2000
      paymentService:
        base-url: http://payment-service:8080
        connect-timeout: 5000
        read-timeout: 10000
      notificationService:
        base-url: http://notification-service:8080
        connect-timeout: 1000
        read-timeout: 2000
        async: true
    
    # 拦截器配置
    interceptors:
      logging:
        log-headers: false
        log-body: true
        max-body-length: 2048
      retry:
        enabled: true
        max-retries: 2
        retry-delay: 500

# 熔断器配置
resilience:
  circuit-breaker:
    failure-rate-threshold: 50
    wait-duration-in-open-state: 10000
    sliding-window-size: 10
  
  rate-limiter:
    limit-for-period: 100
    limit-refresh-period: 1000
    timeout-duration: 1000

# 分布式追踪
tracing:
  enabled: true
  service-name: order-service

2. 数据模型

// Order.java
package com.example.order.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

public class Order {
    private Long id;
    private Long userId;
    private String orderNumber;
    private OrderStatus status;
    private BigDecimal totalAmount;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    private List<OrderItem> items;
    private PaymentInfo paymentInfo;
    private ShippingInfo shippingInfo;
    
    // 构造函数和 Getter/Setter 方法省略...
    
    public enum OrderStatus {
        PENDING,        // 待处理
        CONFIRMED,      // 已确认
        PAID,          // 已支付
        SHIPPED,       // 已发货
        DELIVERED,     // 已送达
        CANCELLED,     // 已取消
        REFUNDED       // 已退款
    }
}

// OrderItem.java
package com.example.order.model;

import java.math.BigDecimal;

public class OrderItem {
    private Long id;
    private Long productId;
    private String productName;
    private BigDecimal price;
    private Integer quantity;
    private BigDecimal subtotal;
    
    // 构造函数和 Getter/Setter 方法省略...
}

// CreateOrderRequest.java
package com.example.order.model;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

public class CreateOrderRequest {
    @NotNull(message = "用户 ID 不能为空")
    private Long userId;
    
    @NotEmpty(message = "订单项不能为空")
    @Valid
    private List<OrderItemRequest> items;
    
    @Valid
    private ShippingInfoRequest shippingInfo;
    
    // 构造函数和 Getter/Setter 方法省略...
    
    public static class OrderItemRequest {
        @NotNull(message = "商品 ID 不能为空")
        private Long productId;
        
        @NotNull(message = "数量不能为空")
        @Min(value = 1, message = "数量必须大于 0")
        private Integer quantity;
        
        // Getter/Setter 方法省略...
    }
}

3. 微服务客户端接口

// UserServiceClient.java
package com.example.order.client;

import com.example.order.model.dto.UserInfo;
import io.github.nemoob.httpclient.annotation.*;

import java.util.concurrent.CompletableFuture;

@HttpClient("${atlas.httpclient.clients.userService.base-url}")
@Interceptor({CircuitBreakerInterceptor.class, RateLimitInterceptor.class})
public interface UserServiceClient {
    
    @GET("/api/users/{id}")
    @Async(timeout = 3000)
    CompletableFuture<UserInfo> getUserInfo(@Path("id") Long userId);
    
    @GET("/api/users/{id}/addresses")
    @Async(timeout = 2000)
    CompletableFuture<List<Address>> getUserAddresses(@Path("id") Long userId);
}

// ProductServiceClient.java
package com.example.order.client;

import com.example.order.model.dto.ProductInfo;
import io.github.nemoob.httpclient.annotation.*;

import java.util.List;
import java.util.concurrent.CompletableFuture;

@HttpClient("${atlas.httpclient.clients.productService.base-url}")
@Interceptor({CircuitBreakerInterceptor.class, DistributedTracingInterceptor.class})
public interface ProductServiceClient {
    
    @GET("/api/products/{id}")
    @Async(timeout = 4000)
    CompletableFuture<ProductInfo> getProductInfo(@Path("id") Long productId);
    
    @POST("/api/products/batch")
    @Async(executor = "batchExecutor", timeout = 5000)
    CompletableFuture<List<ProductInfo>> getProductInfoBatch(@Body List<Long> productIds);
}

// InventoryServiceClient.java
package com.example.order.client;

import com.example.order.model.dto.InventoryInfo;
import com.example.order.model.dto.ReservationRequest;
import com.example.order.model.dto.ReservationResult;
import io.github.nemoob.httpclient.annotation.*;

import java.util.concurrent.CompletableFuture;

@HttpClient("${atlas.httpclient.clients.inventoryService.base-url}")
@Interceptor({CircuitBreakerInterceptor.class, RateLimitInterceptor.class})
public interface InventoryServiceClient {
    
    @GET("/api/inventory/{productId}")
    @Async(timeout = 2000)
    CompletableFuture<InventoryInfo> getInventory(@Path("productId") Long productId);
    
    @POST("/api/inventory/reserve")
    @Async(timeout = 3000, retryCount = 2)
    CompletableFuture<ReservationResult> reserveInventory(@Body ReservationRequest request);
    
    @POST("/api/inventory/release")
    @Async(timeout = 2000)
    CompletableFuture<Void> releaseInventory(@Body String reservationId);
}

// PaymentServiceClient.java
package com.example.order.client;

import com.example.order.model.dto.PaymentRequest;
import com.example.order.model.dto.PaymentResult;
import io.github.nemoob.httpclient.annotation.*;

import java.util.concurrent.CompletableFuture;

@HttpClient("${atlas.httpclient.clients.paymentService.base-url}")
@Interceptor({CircuitBreakerInterceptor.class, DistributedTracingInterceptor.class})
public interface PaymentServiceClient {
    
    @POST("/api/payments/process")
    @Async(timeout = 10000, retryCount = 1)
    CompletableFuture<PaymentResult> processPayment(@Body PaymentRequest request);
    
    @POST("/api/payments/{id}/refund")
    @Async(timeout = 8000)
    CompletableFuture<PaymentResult> refundPayment(@Path("id") String paymentId);
}

// NotificationServiceClient.java
package com.example.order.client;

import com.example.order.model.dto.NotificationRequest;
import io.github.nemoob.httpclient.annotation.*;

import java.util.concurrent.CompletableFuture;

@HttpClient("${atlas.httpclient.clients.notificationService.base-url}")
@Interceptor({RateLimitInterceptor.class})
public interface NotificationServiceClient {
    
    @POST("/api/notifications/send")
    @Async(executor = "notificationExecutor", timeout = 2000)
    CompletableFuture<Void> sendNotification(@Body NotificationRequest request);
    
    @POST("/api/notifications/sms")
    @Async(executor = "notificationExecutor", timeout = 3000)
    CompletableFuture<Void> sendSms(@Body SmsRequest request);
    
    @POST("/api/notifications/email")
    @Async(executor = "notificationExecutor", timeout = 5000)
    CompletableFuture<Void> sendEmail(@Body EmailRequest request);
}

4. 高级拦截器实现

// CircuitBreakerInterceptor.java
package com.example.order.interceptor;

import io.github.nemoob.httpclient.AbstractRequestInterceptor;
import io.github.nemoob.httpclient.RequestContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 熔断器拦截器
 * 实现服务熔断保护机制
 */
@Component
public class CircuitBreakerInterceptor extends AbstractRequestInterceptor {
    
    @Value("${resilience.circuit-breaker.failure-rate-threshold:50}")
    private int failureRateThreshold;
    
    @Value("${resilience.circuit-breaker.wait-duration-in-open-state:10000}")
    private long waitDurationInOpenState;
    
    @Value("${resilience.circuit-breaker.sliding-window-size:10}")
    private int slidingWindowSize;
    
    // 每个服务的熔断器状态
    private final ConcurrentHashMap<String, CircuitBreakerState> circuitBreakers = new ConcurrentHashMap<>();
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        String serviceKey = getServiceKey(context);
        CircuitBreakerState state = circuitBreakers.computeIfAbsent(serviceKey, k -> new CircuitBreakerState());
        
        if (state.isOpen()) {
            if (state.shouldAttemptReset()) {
                state.halfOpen();
            } else {
                throw new RuntimeException("Circuit breaker is OPEN for service: " + serviceKey);
            }
        }
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        String serviceKey = getServiceKey(context);
        CircuitBreakerState state = circuitBreakers.get(serviceKey);
        
        if (state != null) {
            state.recordSuccess();
        }
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        String serviceKey = getServiceKey(context);
        CircuitBreakerState state = circuitBreakers.get(serviceKey);
        
        if (state != null) {
            state.recordFailure();
        }
    }
    
    private String getServiceKey(RequestContext context) {
        String url = context.getRequest().getUrl();
        // 从 URL 中提取服务标识
        return url.split("/")[2]; // 简化实现
    }
    
    /**
     * 熔断器状态
     */
    private class CircuitBreakerState {
        private volatile State state = State.CLOSED;
        private final AtomicInteger failureCount = new AtomicInteger(0);
        private final AtomicInteger successCount = new AtomicInteger(0);
        private final AtomicLong lastFailureTime = new AtomicLong(0);
        
        enum State {
            CLOSED, OPEN, HALF_OPEN
        }
        
        public boolean isOpen() {
            return state == State.OPEN;
        }
        
        public boolean shouldAttemptReset() {
            return System.currentTimeMillis() - lastFailureTime.get() > waitDurationInOpenState;
        }
        
        public void halfOpen() {
            state = State.HALF_OPEN;
        }
        
        public void recordSuccess() {
            successCount.incrementAndGet();
            
            if (state == State.HALF_OPEN) {
                state = State.CLOSED;
                failureCount.set(0);
            }
        }
        
        public void recordFailure() {
            int failures = failureCount.incrementAndGet();
            lastFailureTime.set(System.currentTimeMillis());
            
            int total = failures + successCount.get();
            if (total >= slidingWindowSize) {
                double failureRate = (double) failures / total * 100;
                if (failureRate >= failureRateThreshold) {
                    state = State.OPEN;
                }
            }
        }
    }
}

// RateLimitInterceptor.java
package com.example.order.interceptor;

import io.github.nemoob.httpclient.AbstractRequestInterceptor;
import io.github.nemoob.httpclient.RequestContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 限流拦截器
 * 实现基于令牌桶的限流机制
 */
@Component
public class RateLimitInterceptor extends AbstractRequestInterceptor {
    
    @Value("${resilience.rate-limiter.limit-for-period:100}")
    private int limitForPeriod;
    
    @Value("${resilience.rate-limiter.limit-refresh-period:1000}")
    private long limitRefreshPeriod;
    
    @Value("${resilience.rate-limiter.timeout-duration:1000}")
    private long timeoutDuration;
    
    // 每个服务的限流器
    private final ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        String serviceKey = getServiceKey(context);
        RateLimiter rateLimiter = rateLimiters.computeIfAbsent(serviceKey, k -> new RateLimiter());
        
        if (!rateLimiter.tryAcquire()) {
            throw new RuntimeException("Rate limit exceeded for service: " + serviceKey);
        }
    }
    
    private String getServiceKey(RequestContext context) {
        String url = context.getRequest().getUrl();
        return url.split("/")[2]; // 简化实现
    }
    
    /**
     * 简单的令牌桶限流器
     */
    private class RateLimiter {
        private final AtomicInteger tokens = new AtomicInteger(limitForPeriod);
        private final AtomicLong lastRefreshTime = new AtomicLong(System.currentTimeMillis());
        
        public boolean tryAcquire() {
            refreshTokens();
            return tokens.getAndDecrement() > 0;
        }
        
        private void refreshTokens() {
            long now = System.currentTimeMillis();
            long lastRefresh = lastRefreshTime.get();
            
            if (now - lastRefresh >= limitRefreshPeriod) {
                if (lastRefreshTime.compareAndSet(lastRefresh, now)) {
                    tokens.set(limitForPeriod);
                }
            }
        }
    }
}

// DistributedTracingInterceptor.java
package com.example.order.interceptor;

import io.github.nemoob.httpclient.AbstractRequestInterceptor;
import io.github.nemoob.httpclient.RequestContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.UUID;

/**
 * 分布式追踪拦截器
 * 为请求添加追踪标识
 */
@Component
public class DistributedTracingInterceptor extends AbstractRequestInterceptor {
    
    @Value("${tracing.service-name:order-service}")
    private String serviceName;
    
    private static final String TRACE_ID_HEADER = "X-Trace-Id";
    private static final String SPAN_ID_HEADER = "X-Span-Id";
    private static final String PARENT_SPAN_ID_HEADER = "X-Parent-Span-Id";
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        String traceId = getOrCreateTraceId();
        String spanId = UUID.randomUUID().toString();
        String parentSpanId = getCurrentSpanId();
        
        // 添加追踪头
        context.getRequest().getHeaders().put(TRACE_ID_HEADER, traceId);
        context.getRequest().getHeaders().put(SPAN_ID_HEADER, spanId);
        if (parentSpanId != null) {
            context.getRequest().getHeaders().put(PARENT_SPAN_ID_HEADER, parentSpanId);
        }
        
        // 设置到上下文
        context.setAttribute("traceId", traceId);
        context.setAttribute("spanId", spanId);
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        String traceId = (String) context.getAttribute("traceId");
        String spanId = (String) context.getAttribute("spanId");
        long duration = context.getEndTime() - context.getStartTime();
        
        // 记录追踪信息
        System.out.printf("[TRACE] %s - %s: %s %s (duration: %dms)%n",
            traceId, spanId,
            context.getRequest().getMethod(),
            context.getRequest().getUrl(),
            duration
        );
    }
    
    private String getOrCreateTraceId() {
        // 简化实现,实际应该从 ThreadLocal 或 MDC 中获取
        return UUID.randomUUID().toString();
    }
    
    private String getCurrentSpanId() {
        // 简化实现,实际应该从当前上下文中获取
        return null;
    }
}

5. 订单编排服务

// OrderOrchestrationService.java
package com.example.order.service;

import com.example.order.client.*;
import com.example.order.model.*;
import com.example.order.model.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 订单编排服务
 * 协调多个微服务完成订单处理流程
 */
@Service
public class OrderOrchestrationService {
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    @Autowired
    private ProductServiceClient productServiceClient;
    
    @Autowired
    private InventoryServiceClient inventoryServiceClient;
    
    @Autowired
    private PaymentServiceClient paymentServiceClient;
    
    @Autowired
    private NotificationServiceClient notificationServiceClient;
    
    /**
     * 创建订单的完整流程
     */
    @Transactional
    public CompletableFuture<Order> createOrder(CreateOrderRequest request) {
        return validateUser(request.getUserId())
            .thenCompose(userInfo -> validateAndReserveProducts(request.getItems()))
            .thenCompose(reservationResults -> {
                // 计算订单总金额
                BigDecimal totalAmount = calculateTotalAmount(reservationResults);
                
                // 创建订单对象
                Order order = createOrderEntity(request, totalAmount);
                
                // 处理支付
                return processPayment(order)
                    .thenCompose(paymentResult -> {
                        if (paymentResult.isSuccess()) {
                            // 支付成功,确认订单
                            order.setStatus(Order.OrderStatus.PAID);
                            return confirmOrder(order)
                                .thenCompose(confirmedOrder -> sendNotifications(confirmedOrder))
                                .thenApply(v -> order);
                        } else {
                            // 支付失败,释放库存
                            return releaseInventory(reservationResults)
                                .thenCompose(v -> {
                                    throw new RuntimeException("支付失败: " + paymentResult.getErrorMessage());
                                });
                        }
                    });
            })
            .exceptionally(throwable -> {
                // 异常处理:回滚操作
                handleOrderCreationFailure(throwable);
                throw new RuntimeException("订单创建失败", throwable);
            });
    }
    
    /**
     * 验证用户信息
     */
    private CompletableFuture<UserInfo> validateUser(Long userId) {
        return userServiceClient.getUserInfo(userId)
            .thenApply(userInfo -> {
                if (userInfo == null) {
                    throw new RuntimeException("用户不存在: " + userId);
                }
                if (!userInfo.isActive()) {
                    throw new RuntimeException("用户账户已被禁用: " + userId);
                }
                return userInfo;
            });
    }
    
    /**
     * 验证商品并预留库存
     */
    private CompletableFuture<List<ReservationResult>> validateAndReserveProducts(List<CreateOrderRequest.OrderItemRequest> items) {
        // 批量获取商品信息
        List<Long> productIds = items.stream()
            .map(CreateOrderRequest.OrderItemRequest::getProductId)
            .collect(Collectors.toList());
        
        return productServiceClient.getProductInfoBatch(productIds)
            .thenCompose(productInfos -> {
                // 验证商品信息
                validateProducts(productInfos, items);
                
                // 并行预留库存
                List<CompletableFuture<ReservationResult>> reservationFutures = items.stream()
                    .map(item -> {
                        ReservationRequest reservationRequest = new ReservationRequest(
                            item.getProductId(),
                            item.getQuantity(),
                            generateReservationId()
                        );
                        return inventoryServiceClient.reserveInventory(reservationRequest);
                    })
                    .collect(Collectors.toList());
                
                return CompletableFuture.allOf(reservationFutures.toArray(new CompletableFuture[0]))
                    .thenApply(v -> reservationFutures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList()));
            });
    }
    
    /**
     * 处理支付
     */
    private CompletableFuture<PaymentResult> processPayment(Order order) {
        PaymentRequest paymentRequest = new PaymentRequest(
            order.getId(),
            order.getUserId(),
            order.getTotalAmount(),
            "ORDER_PAYMENT"
        );
        
        return paymentServiceClient.processPayment(paymentRequest)
            .thenApply(result -> {
                // 更新订单支付信息
                order.setPaymentInfo(new PaymentInfo(
                    result.getPaymentId(),
                    result.getPaymentMethod(),
                    result.getTransactionId()
                ));
                return result;
            });
    }
    
    /**
     * 确认订单
     */
    private CompletableFuture<Order> confirmOrder(Order order) {
        // 这里应该保存订单到数据库
        // 简化实现,直接返回
        return CompletableFuture.completedFuture(order);
    }
    
    /**
     * 发送通知
     */
    private CompletableFuture<Void> sendNotifications(Order order) {
        // 并行发送多种通知
        CompletableFuture<Void> emailNotification = sendEmailNotification(order);
        CompletableFuture<Void> smsNotification = sendSmsNotification(order);
        CompletableFuture<Void> pushNotification = sendPushNotification(order);
        
        return CompletableFuture.allOf(emailNotification, smsNotification, pushNotification)
            .exceptionally(throwable -> {
                // 通知失败不影响订单创建
                System.err.println("发送通知失败: " + throwable.getMessage());
                return null;
            });
    }
    
    /**
     * 释放库存
     */
    private CompletableFuture<Void> releaseInventory(List<ReservationResult> reservationResults) {
        List<CompletableFuture<Void>> releaseFutures = reservationResults.stream()
            .filter(ReservationResult::isSuccess)
            .map(result -> inventoryServiceClient.releaseInventory(result.getReservationId()))
            .collect(Collectors.toList());
        
        return CompletableFuture.allOf(releaseFutures.toArray(new CompletableFuture[0]));
    }
    
    /**
     * 发送邮件通知
     */
    private CompletableFuture<Void> sendEmailNotification(Order order) {
        EmailRequest emailRequest = new EmailRequest(
            order.getUserId(),
            "订单确认",
            "您的订单 " + order.getOrderNumber() + " 已确认,感谢您的购买!"
        );
        return notificationServiceClient.sendEmail(emailRequest);
    }
    
    /**
     * 发送短信通知
     */
    private CompletableFuture<Void> sendSmsNotification(Order order) {
        SmsRequest smsRequest = new SmsRequest(
            order.getUserId(),
            "订单 " + order.getOrderNumber() + " 已确认"
        );
        return notificationServiceClient.sendSms(smsRequest);
    }
    
    /**
     * 发送推送通知
     */
    private CompletableFuture<Void> sendPushNotification(Order order) {
        NotificationRequest notificationRequest = new NotificationRequest(
            order.getUserId(),
            "订单确认",
            "您的订单已确认",
            "ORDER_CONFIRMED"
        );
        return notificationServiceClient.sendNotification(notificationRequest);
    }
    
    /**
     * 验证商品信息
     */
    private void validateProducts(List<ProductInfo> productInfos, List<CreateOrderRequest.OrderItemRequest> items) {
        if (productInfos.size() != items.size()) {
            throw new RuntimeException("部分商品不存在");
        }
        
        for (ProductInfo productInfo : productInfos) {
            if (!productInfo.isAvailable()) {
                throw new RuntimeException("商品不可用: " + productInfo.getName());
            }
        }
    }
    
    /**
     * 计算订单总金额
     */
    private BigDecimal calculateTotalAmount(List<ReservationResult> reservationResults) {
        return reservationResults.stream()
            .filter(ReservationResult::isSuccess)
            .map(result -> result.getPrice().multiply(BigDecimal.valueOf(result.getQuantity())))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    /**
     * 创建订单实体
     */
    private Order createOrderEntity(CreateOrderRequest request, BigDecimal totalAmount) {
        Order order = new Order();
        order.setUserId(request.getUserId());
        order.setOrderNumber(generateOrderNumber());
        order.setStatus(Order.OrderStatus.PENDING);
        order.setTotalAmount(totalAmount);
        order.setCreatedAt(LocalDateTime.now());
        
        // 设置订单项
        List<OrderItem> orderItems = request.getItems().stream()
            .map(item -> {
                OrderItem orderItem = new OrderItem();
                orderItem.setProductId(item.getProductId());
                orderItem.setQuantity(item.getQuantity());
                return orderItem;
            })
            .collect(Collectors.toList());
        order.setItems(orderItems);
        
        return order;
    }
    
    /**
     * 生成订单号
     */
    private String generateOrderNumber() {
        return "ORD" + System.currentTimeMillis();
    }
    
    /**
     * 生成预留ID
     */
    private String generateReservationId() {
        return "RSV" + System.currentTimeMillis() + "_" + Thread.currentThread().getId();
    }
    
    /**
     * 处理订单创建失败
     */
    private void handleOrderCreationFailure(Throwable throwable) {
        System.err.println("订单创建失败,执行回滚操作: " + throwable.getMessage());
        // 这里应该实现具体的回滚逻辑
    }
}
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]