文章目录
接上篇
HandlerExceptionResolver
- 异常处理的原理剖析
思考题:在微服务架构下,如何设计跨服务的异常处理适配器,实现异常信息的标准化和跨服务传播?
Spring MVC整体设计核心解密参阅:Spring MVC设计精粹:源码级架构解析与实践指南
一、问题分析与设计目标
在微服务架构中,异常处理面临三大核心挑战:
- 异常信息碎片化:各服务异常格式不统一,难以聚合分析
- 调用链断裂:异常在服务间传播时上下文丢失
- 处理策略分散:每个服务单独实现异常处理,重复工作
设计目标
- 标准化:统一异常数据格式
- 可追踪:保持分布式追踪完整性
- 自适应:根据异常类型自动选择处理策略
- 可观测:提供完整的异常监控能力
二、整体架构设计
三、核心组件实现
1. 统一异常响应体设计
// 标准化异常响应体
public class UnifiedExceptionResponse {
private String code; // 错误代码
private String message; // 用户可读消息
private String detail; // 技术详情
private String service; // 异常来源服务
private String traceId; // 分布式追踪ID
private long timestamp; // 时间戳
private String path; // 请求路径
private Map<String, Object> context; // 异常上下文
// 构造方法
public static UnifiedExceptionResponse of(ErrorCode errorCode,
String serviceName,
String traceId,
String path) {
return new UnifiedExceptionResponse(
errorCode.getCode(),
errorCode.getMessage(),
null,
serviceName,
traceId,
System.currentTimeMillis(),
path,
new HashMap<>()
);
}
}
// 错误代码枚举
public enum ErrorCode {
// 业务错误
USER_NOT_FOUND("B1001", "用户不存在"),
INVALID_PARAMETER("B1002", "参数无效"),
// 系统错误
SERVICE_UNAVAILABLE("S5001", "服务暂时不可用"),
NETWORK_TIMEOUT("S5002", "网络超时"),
// 第三方错误
THIRD_PARTY_ERROR("T3001", "第三方服务异常");
private final String code;
private final String message;
// 构造方法等
}
2. 异常处理适配器核心实现
/**
* 微服务异常处理适配器
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MicroserviceExceptionAdapter implements HandlerExceptionResolver {
@Autowired
private TraceContext traceContext;
@Autowired
private ServiceRegistry serviceRegistry;
@Autowired
private ExceptionConfigRepository configRepository;
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
// 1. 转换为统一异常响应
UnifiedExceptionResponse unifiedResponse = convertToUnifiedResponse(ex, request);
// 2. 增强异常信息
enhanceExceptionResponse(unifiedResponse, ex, request);
// 3. 记录异常日志
logException(ex, unifiedResponse);
// 4. 发送异常监控
sendExceptionMetrics(unifiedResponse);
// 5. 返回标准化响应
return buildModelAndView(response, unifiedResponse);
}
private UnifiedExceptionResponse convertToUnifiedResponse(Exception ex, HttpServletRequest request) {
// 识别异常类型并映射到标准错误码
ErrorCode errorCode = determineErrorCode(ex);
return UnifiedExceptionResponse.of(
errorCode,
serviceRegistry.getCurrentServiceName(),
traceContext.getTraceId(),
request.getRequestURI()
);
}
private ErrorCode determineErrorCode(Exception ex) {
// 异常类型到错误码的映射
if (ex instanceof UserNotFoundException) {
return ErrorCode.USER_NOT_FOUND;
} else if (ex instanceof HttpClientErrorException) {
return ErrorCode.THIRD_PARTY_ERROR;
} else if (ex instanceof TimeoutException) {
return ErrorCode.NETWORK_TIMEOUT;
}
// 默认系统错误
return ErrorCode.SERVICE_UNAVAILABLE;
}
}
3. 分布式异常传播器
/**
* 异常传播处理器(用于RestTemplate/Feign调用)
*/
@Component
public class ExceptionPropagationHandler {
@Autowired
private TraceContext traceContext;
/**
* 处理HTTP响应,转换异常
*/
public void handleResponse(ClientHttpResponse response) throws IOException {
if (!response.getStatusCode().is2xxSuccessful()) {
// 读取异常响应体
UnifiedExceptionResponse exceptionResponse = readErrorResponse(response);
// 重建并抛出业务异常
throw rebuildException(exceptionResponse);
}
}
private UnifiedExceptionResponse readErrorResponse(ClientHttpResponse response) throws IOException {
String body = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
try {
return objectMapper.readValue(body, UnifiedExceptionResponse.class);
} catch (Exception e) {
// fallback: 处理非标准异常响应
return createFallbackResponse(response, body);
}
}
private Exception rebuildException(UnifiedExceptionResponse response) {
// 根据错误码重建异常
switch (response.getCode()) {
case "B1001":
return new UserNotFoundException(response.getMessage());
case "S5002":
return new TimeoutException(response.getMessage());
default:
return new ServiceException(response.getCode(), response.getMessage());
}
}
/**
* 为出站请求添加异常处理头信息
*/
public void addExceptionHeaders(HttpRequest request) {
request.getHeaders().add("X-Exception-Handling", "standardized");
request.getHeaders().add("X-Trace-Id", traceContext.getTraceId());
}
}
4. 异常配置管理
/**
* 动态异常配置管理器
*/
@Component
@RefreshScope
public class DynamicExceptionConfig {
private Map<String, ExceptionHandlingStrategy> strategyMap = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
// 从配置中心加载异常处理策略
loadExceptionStrategies();
}
@Scheduled(fixedRate = 300000) // 每5分钟刷新
public void refreshStrategies() {
loadExceptionStrategies();
}
private void loadExceptionStrategies() {
List<ExceptionStrategyConfig> configs = configRepository.findAll();
configs.forEach(config -> {
strategyMap.put(config.getExceptionPattern(),
createStrategy(config));
});
}
public ExceptionHandlingStrategy getStrategy(String exceptionClass) {
return strategyMap.getOrDefault(exceptionClass,
DefaultExceptionHandlingStrategy.INSTANCE);
}
}
// 异常处理策略
public interface ExceptionHandlingStrategy {
UnifiedExceptionResponse handle(Exception ex, HttpServletRequest request);
boolean shouldRetry();
Duration retryDelay();
Level logLevel();
}
四、集成实施方案
1. RestTemplate集成
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate exceptionAwareRestTemplate(ExceptionPropagationHandler handler) {
RestTemplate restTemplate = new RestTemplate();
// 添加异常处理拦截器
restTemplate.getInterceptors().add((request, body, execution) -> {
handler.addExceptionHeaders(request);
try {
ClientHttpResponse response = execution.execute(request, body);
handler.handleResponse(response);
return response;
} catch (Exception ex) {
throw handler.enrichException(ex, request);
}
});
return restTemplate;
}
}
2. Feign Client集成
@Configuration
public class FeignConfig {
@Bean
public ErrorDecoder feignErrorDecoder(ExceptionPropagationHandler handler) {
return (methodKey, response) -> {
try {
handler.handleResponse(response);
return new DefaultErrorDecoder().decode(methodKey, response);
} catch (Exception ex) {
return handler.rebuildExceptionFromResponse(response);
}
};
}
@Bean
public RequestInterceptor feignExceptionInterceptor(ExceptionPropagationHandler handler) {
return template -> {
template.header("X-Exception-Handling", "standardized");
template.header("X-Trace-Id", handler.getCurrentTraceId());
};
}
}
3. Spring MVC全局异常处理
@RestControllerAdvice
public class GlobalMicroserviceExceptionHandler {
@Autowired
private MicroserviceExceptionAdapter exceptionAdapter;
@ExceptionHandler(Exception.class)
public ResponseEntity<UnifiedExceptionResponse> handleAllExceptions(
Exception ex, WebRequest request) {
HttpServletRequest servletRequest = ((ServletWebRequest) request).getRequest();
UnifiedExceptionResponse response = exceptionAdapter.convertToUnifiedResponse(ex, servletRequest);
return ResponseEntity.status(determineHttpStatus(response))
.header("X-Trace-Id", response.getTraceId())
.body(response);
}
private HttpStatus determineHttpStatus(UnifiedExceptionResponse response) {
// 根据错误码确定HTTP状态码
if (response.getCode().startsWith("B")) {
return HttpStatus.BAD_REQUEST;
} else if (response.getCode().startsWith("S")) {
return HttpStatus.INTERNAL_SERVER_ERROR;
} else if (response.getCode().startsWith("T")) {
return HttpStatus.BAD_GATEWAY;
}
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
五、监控与观测能力
1. 异常指标收集
@Component
public class ExceptionMetricsCollector {
@Autowired
private MeterRegistry meterRegistry;
private final Map<String, Counter> exceptionCounters = new ConcurrentHashMap<>();
public void recordException(UnifiedExceptionResponse response) {
String metricName = "exception." + response.getService() + "." + response.getCode();
Counter counter = exceptionCounters.computeIfAbsent(metricName,
key -> meterRegistry.counter(key, "type", response.getCode()));
counter.increment();
// 记录异常分布
meterRegistry.timer("exception.duration",
"service", response.getService(),
"code", response.getCode())
.record(Duration.ofMillis(System.currentTimeMillis() - response.getTimestamp()));
}
}
2. 分布式追踪集成
@Component
public class ExceptionTracingIntegration {
@Autowired
private Tracer tracer;
public void addExceptionToTrace(UnifiedExceptionResponse response) {
Span currentSpan = tracer.currentSpan();
if (currentSpan != null) {
currentSpan.tag("exception.code", response.getCode());
currentSpan.tag("exception.service", response.getService());
currentSpan.tag("exception.message", response.getMessage());
currentSpan.log(Map.of(
"event", "exception",
"detail", response.getDetail(),
"timestamp", response.getTimestamp()
));
}
}
}
六、部署与运维方案
1. 配置管理
# application-exception.yml
exception:
strategy:
patterns:
- pattern: "com.example.**.UserNotFoundException"
retry: false
log-level: "WARN"
http-status: 404
- pattern: "**.TimeoutException"
retry: true
retry-delay: "1000ms"
log-level: "ERROR"
http-status: 504
propagation:
enabled: true
include-stacktrace: false
max-depth: 3
monitoring:
enabled: true
sampling-rate: 0.1
2. 健康检查与就绪探针
@RestController
public class ExceptionHealthIndicator {
@Autowired
private ExceptionMetricsCollector metricsCollector;
@GetMapping("/health/exception")
public ResponseEntity<Map<String, Object>> exceptionHealth() {
Map<String, Object> health = new HashMap<>();
// 检查异常率是否在阈值内
double errorRate = calculateErrorRate();
health.put("errorRate", errorRate);
health.put("status", errorRate < 0.01 ? "UP" : "DEGRADED");
health.put("threshold", 0.01);
return ResponseEntity.ok(health);
}
}
七、成效与价值
通过这套跨服务异常处理适配器,实现了:
- 标准化异常处理:所有服务产生统一格式的异常响应
- 完整调用链追踪:异常在服务间传播时不丢失上下文
- 智能异常处理:根据配置自动选择重试、降级等策略
- 全面可观测性:提供异常监控、告警、分析能力
- 开发效率提升:减少重复异常处理代码,专注业务逻辑
监控看板示例:
总结
该跨服务异常处理适配器通过 标准化响应格式、传播上下文信息 和 统一处理策略,可以将微服务架构下分散的异常处理能力整合为一个可观测、可管理、可扩展的基础设施组件。它不仅是技术组件,更是一种治理理念,将 “异常” 变为一种有价值的 “数据”,能显著提升微服务系统的可维护性和可靠性。
详细结构设计: