深度解析 Spring MVC `@ControllerAdvice` 注解

深度解析 Spring MVC @ControllerAdvice 注解

@ControllerAdvice 是 Spring MVC 中实现全局处理的核心注解,它提供了一种声明式的方式来统一处理控制器层级的通用功能。本文将全面剖析其工作原理、源码实现、应用场景及最佳实践。

一、注解定义与核心作用

1. 源码定义

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
public @interface ControllerAdvice {
    @AliasFor("basePackages")
    String[] value() default {};
    
    @AliasFor("value")
    String[] basePackages() default {};
    
    Class<?>[] basePackageClasses() default {};
    
    Class<?>[] assignableTypes() default {};
    
    Class<? extends Annotation>[] annotations() default {};
}

2. 核心作用

  • 统一异常处理:全局处理控制器抛出的异常
  • 全局数据绑定:添加所有控制器共享的模型属性
  • 全局请求预处理:在控制器执行前进行通用处理
  • 全局后处理:在控制器执行后进行通用操作

二、工作原理与处理流程

1. 全局处理流程

客户端 DispatcherServlet HandlerAdapter ControllerAdvice Controller 发送请求 获取处理器适配器 1. 调用@ModelAttribute方法 返回模型属性 2. 调用控制器方法 执行业务逻辑 抛出异常 3. 调用@ExceptionHandler方法 返回结果 alt [控制器抛出异常] [正常执行] 4. 调用返回后处理方法(如有) 返回处理结果 返回响应 客户端 DispatcherServlet HandlerAdapter ControllerAdvice Controller

2. 核心处理阶段

  1. 模型初始化:调用 @ModelAttribute 方法准备全局数据
  2. 请求处理:执行目标控制器方法
  3. 异常捕获:如出现异常,调用匹配的 @ExceptionHandler
  4. 响应后处理:调用 @ResponseBodyAdvice 方法处理返回结果

三、源码深度解析

1. 控制器增强扫描

ControllerAdviceBean 负责扫描和管理所有 @ControllerAdvice 组件:

class ControllerAdviceBean implements Ordered {
    public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
        // 扫描带@ControllerAdvice的Bean
        return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, Object.class)
            .values().stream()
            .filter(bean -> AnnotationUtils.findAnnotation(bean.getClass(), ControllerAdvice.class) != null)
            .map(bean -> new ControllerAdviceBean(bean, context))
            .sorted(OrderComparator.INSTANCE)
            .collect(Collectors.toList());
    }
}

2. 异常处理机制

ExceptionHandlerExceptionResolver 负责异常派发:

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver {
    protected ModelAndView doResolveException(HttpServletRequest request, 
        HttpServletResponse response, Object handler, Exception ex) {
        
        // 1. 查找控制器内部的异常处理器
        if (handler instanceof HandlerMethod) {
            Method method = ((HandlerMethod) handler).getMethod();
            Method exceptionHandlerMethod = findExceptionHandlerMethod(method, ex);
            if (exceptionHandlerMethod != null) {
                return invokeExceptionHandlerMethod(exceptionHandlerMethod, handler, ex, request, response);
            }
        }
        
        // 2. 查找@ControllerAdvice中的全局异常处理器
        for (Object advice : controllerAdviceCache) {
            Method exceptionHandlerMethod = findExceptionHandlerMethod(advice, ex);
            if (exceptionHandlerMethod != null) {
                return invokeExceptionHandlerMethod(exceptionHandlerMethod, advice, ex, request, response);
            }
        }
        
        return null;
    }
}

3. 全局数据绑定

RequestMappingHandlerAdapter 处理全局模型属性:

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter {
    private void updateModelAttributes(ModelMap model, Object handler, 
        NativeWebRequest request) throws Exception {
        
        // 获取所有@ControllerAdvice
        for (ControllerAdviceBean advice : controllerAdviceCache) {
            // 执行@ModelAttribute方法
            for (Method method : advice.getModelAttributeMethods()) {
                ModelAttribute ann = method.getAnnotation(ModelAttribute.class);
                String name = getNameForModelAttribute(ann, method);
                Object value = method.invoke(advice.resolveBean());
                model.addAttribute(name, value);
            }
        }
    }
}

四、核心应用场景

1. 全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(new ErrorResponse("RESOURCE_NOT_FOUND", ex.getMessage()));
    }
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ValidationErrors> handleValidationErrors(MethodArgumentNotValidException ex) {
        List<FieldError> errors = ex.getBindingResult().getFieldErrors()
            .stream()
            .map(error -> new FieldError(error.getField(), error.getDefaultMessage()))
            .collect(Collectors.toList());
        return ResponseEntity.badRequest().body(new ValidationErrors(errors));
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(new ErrorResponse("SERVER_ERROR", "Internal server error"));
    }
}

2. 全局数据绑定

@ControllerAdvice
public class GlobalModelAttributes {
    
    @ModelAttribute("appVersion")
    public String appVersion() {
        return "1.5.2";
    }
    
    @ModelAttribute("currentYear")
    public int currentYear() {
        return Year.now().getValue();
    }
    
    @ModelAttribute("environment")
    public String environment() {
        return System.getProperty("env", "development");
    }
}

3. 全局请求预处理

@ControllerAdvice
public class RequestPreProcessor {
    
    @ModelAttribute
    public void addRequestInfo(HttpServletRequest request, Model model) {
        model.addAttribute("requestId", UUID.randomUUID().toString());
        model.addAttribute("clientIp", request.getRemoteAddr());
    }
    
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 全局禁止绑定敏感字段
        binder.setDisallowedFields("internalToken", "securityCode");
    }
}

4. 全局响应后处理

@ControllerAdvice
public class GlobalResponseProcessor implements ResponseBodyAdvice<Object> {
    
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.hasMethodAnnotation(ResponseBody.class) || 
               returnType.getContainingClass().isAnnotationPresent(RestController.class);
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType contentType,
        Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) {
        
        // 统一封装响应格式
        if (!(body instanceof ApiResponse)) {
            return new ApiResponse<>(body);
        }
        return body;
    }
}

public class ApiResponse<T> {
    private String code = "SUCCESS";
    private T data;
    private long timestamp = System.currentTimeMillis();
    
    // 构造器和方法
}

五、高级特性与配置

1. 限定作用范围

// 仅作用于指定包下的控制器
@ControllerAdvice(basePackages = "com.example.product.controllers")

// 仅作用于指定的控制器类
@ControllerAdvice(assignableTypes = {UserController.class, OrderController.class})

// 仅作用于带特定注解的控制器
@ControllerAdvice(annotations = RestController.class)

// 组合限定条件
@ControllerAdvice(
    basePackages = "com.example.api",
    annotations = VersionedAPI.class
)

2. 响应内容协商

@ControllerAdvice
public class ContentNegotiationAdvice implements RequestBodyAdvice, ResponseBodyAdvice<Object> {
    
    // 请求体处理前
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    
    // 响应体处理前
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType contentType,
        Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) {
        
        // 根据Accept头动态调整响应格式
        if (request.getHeaders().getAccept().contains(MediaType.APPLICATION_XML)) {
            return new XmlResponse(body);
        }
        return body;
    }
}

3. 多模块化处理

// 核心模块处理器
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice(assignableTypes = CoreController.class)
public class CoreExceptionHandler {
    @ExceptionHandler(CoreException.class)
    public ResponseEntity<ErrorResponse> handleCoreException() {
        // 核心模块特有处理
    }
}

// 通用处理器
@Order(Ordered.LOWEST_PRECEDENCE)
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGenericException() {
        // 通用处理
    }
}

六、最佳实践与设计模式

1. 分层处理架构

graph TD
    A[控制器执行] --> B{是否异常}
    B -->|是| C[控制器内部@ExceptionHandler]
    C -->|未处理| D[模块级@ControllerAdvice]
    D -->|未处理| E[全局@ControllerAdvice]
    E --> F[返回错误响应]
    B -->|正常| G[控制器返回结果]
    G --> H[全局ResponseBodyAdvice]
    H --> I[返回统一响应]

2. 响应标准化

统一响应格式规范

{
  "success": true,
  "code": "SUCCESS",
  "message": "操作成功",
  "data": {},
  "timestamp": 1630425600000,
  "requestId": "req_123456"
}

实现代码

@ControllerAdvice
public class StandardResponseAdvice implements ResponseBodyAdvice<Object> {
    
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType contentType,
        Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) {
        
        if (body instanceof StandardResponse) {
            return body;
        }
        
        // 创建统一响应对象
        StandardResponse<Object> result = new StandardResponse<>();
        result.setData(body);
        result.setSuccess(true);
        result.setTimestamp(System.currentTimeMillis());
        
        // 设置请求ID(如果存在)
        Object requestId = request.getHeaders().getFirst("X-Request-ID");
        if (requestId != null) {
            result.setRequestId(requestId.toString());
        }
        
        return result;
    }
}

3. 安全实践

敏感信息处理

@ControllerAdvice
public class SecurityEnhancement {
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception ex, 
        HttpServletRequest request) {
        
        // 生产环境隐藏异常详情
        if ("production".equals(environment)) {
            return ResponseEntity.internalServerError()
                .body(new ErrorResponse("SERVER_ERROR", "Internal server error"));
        } else {
            return ResponseEntity.internalServerError()
                .body(new ErrorResponse("SERVER_ERROR", ex.getMessage()));
        }
    }
    
    @ModelAttribute
    public void removeSensitiveHeaders(HttpServletResponse response) {
        // 移除敏感头信息
        response.setHeader("X-Powered-By", "");
        response.setHeader("Server", "Secure-Server");
    }
}

七、企业级应用方案

1. 微服务架构集成

@ControllerAdvice
public class MicroserviceIntegration {
    
    // 分布式链路追踪
    @ModelAttribute
    public void addTraceInfo(@RequestHeader(value = "X-B3-TraceId", required = false) String traceId, 
                           Model model) {
        if (traceId == null) {
            traceId = IdGenerator.generateTraceId();
        }
        model.addAttribute("traceId", traceId);
        MDC.put("traceId", traceId);
    }
    
    // 微服务异常转换
    @ExceptionHandler(FeignException.class)
    public ResponseEntity<ErrorResponse> handleFeignException(FeignException ex) {
        ErrorResponse error = parseFeignException(ex);
        return ResponseEntity.status(ex.status()).body(error);
    }
}

2. 监控与指标收集

@ControllerAdvice
public class MetricsCollector {
    
    private final MeterRegistry meterRegistry;
    
    public MetricsCollector(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    // 请求计数器
    @ModelAttribute
    public void countRequest(HttpServletRequest request) {
        String uri = request.getRequestURI();
        Counter.builder("http.requests")
            .tag("method", request.getMethod())
            .tag("uri", uri)
            .tag("status", "started")
            .register(meterRegistry)
            .increment();
    }
    
    // 异常指标
    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> handleAndRecordException(Exception ex, 
        HttpServletRequest request, HttpServletResponse response) {
        
        String uri = request.getRequestURI();
        Counter.builder("http.errors")
            .tag("method", request.getMethod())
            .tag("uri", uri)
            .tag("exception", ex.getClass().getSimpleName())
            .register(meterRegistry)
            .increment();
        
        return ResponseEntity.status(500).build();
    }
}

3. API 版本控制

@ControllerAdvice
public class ApiVersionHandler {
    
    @ModelAttribute
    public void checkApiVersion(@RequestHeader("API-Version") String apiVersion, 
                              HttpServletResponse response) {
        response.setHeader("API-Version", apiVersion);
        
        if (!"v2".equals(apiVersion) && !"v3".equals(apiVersion)) {
            throw new UnsupportedApiVersionException("Unsupported API version");
        }
    }
    
    @ExceptionHandler(UnsupportedApiVersionException.class)
    public ResponseEntity<ErrorResponse> handleUnsupportedVersion() {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
            .body(new ErrorResponse("UNSUPPORTED_VERSION", "Please use v2 or v3 API"));
    }
}

八、常见问题解决方案

1. 全局处理器未生效

解决方案

// 1. 确保组件扫描包含
@ComponentScan(basePackages = "com.example.advice")

// 2. 检查Order顺序
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE) // 提高优先级

// 3. 确认方法访问权限
@ControllerAdvice
public class MyAdvice {
    @ExceptionHandler // public方法
    public ResponseEntity<?> handle() { ... }
}

2. 与控制器处理器冲突

解决方案

// 1. 明确职责划分
// 控制器处理业务异常,全局处理技术异常

// 2. 使用优先级控制
@Order(Ordered.LOWEST_PRECEDENCE)
@ControllerAdvice
public class FallbackAdvice {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> fallback() { ... }
}

// 3. 在控制器中重定向到全局处理
@RestController
public class ProductController {
    @ExceptionHandler(ProductException.class)
    public void handleProductException(ProductException ex) throws Exception {
        // 重定向到全局处理
        throw new GlobalHandlingException(ex);
    }
}

3. 跨域问题

解决方案

// 全局CORS配置
@ControllerAdvice
public class CorsControllerAdvice implements CorsConfigurationSource {
    
    @Override
    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setMaxAge(3600L);
        return config;
    }
}

九、未来发展方向

1. 响应式架构支持

@ControllerAdvice
public class ReactiveControllerAdvice {
    
    @ExceptionHandler
    public Mono<ResponseEntity<String>> handleException(ServerWebExchange exchange, Exception ex) {
        return Mono.just(ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body("Error occurred: " + ex.getMessage()));
    }
    
    @ModelAttribute
    public Mono<Void> addAttributes(ServerWebExchange exchange) {
        return Mono.fromRunnable(() -> 
            exchange.getAttributes().put("requestTime", Instant.now()));
    }
}

2. 智能异常诊断

@ControllerAdvice
public class AIDiagnosisAdvice {
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<DiagnosisResult> handleWithDiagnosis(Exception ex, 
        @Autowired AIDiagnosisService diagnosisService) {
        
        Diagnosis diagnosis = diagnosisService.diagnose(ex);
        return ResponseEntity.status(diagnosis.getRecommendedStatus())
            .body(new DiagnosisResult(diagnosis));
    }
}

3. 自适应安全响应

@ControllerAdvice
public class AdaptiveSecurityAdvice {
    
    @ExceptionHandler(SecurityException.class)
    public ResponseEntity<?> handleSecurityException(SecurityException ex, 
        HttpServletRequest request) {
        
        ClientInfo client = securityService.analyzeClient(request);
        return ResponseEntity
            .status(client.isSuspicious() ? 403 : 401)
            .header("X-Security-Level", client.threatLevel())
            .build();
    }
}

十、总结

@ControllerAdvice 是 Spring MVC 中实现全局处理的核心机制,其关键优势在于:

  1. 集中管理:统一处理横切关注点
  2. 模块化设计:分模块实现不同关注点
  3. 灵活扩展:通过优先级和限定条件控制处理范围
  4. 标准化支持:实现统一响应格式和错误处理

在实际应用中应当:

  • 合理分层:控制器级处理 > 模块级处理 > 全局处理
  • 标准化响应:统一 API 响应格式
  • 安全隔离:控制异常信息暴露
  • 性能监控:集成指标收集机制

在企业级系统中:

  • 微服务架构:处理分布式系统的共性需求
  • 云原生环境:适配 Kubernetes 等环境特性
  • 多租户系统:处理租户隔离的通用逻辑
  • 国际化支持:统一处理多语言资源

掌握 @ControllerAdvice 的高级特性和最佳实践,能够帮助开发者:

  • 构建高内聚、低耦合的控制器层
  • 实现一致的用户体验
  • 提升系统可维护性和扩展性
  • 构建企业级的标准化处理流程

作为 Spring MVC 全局处理的基石,@ControllerAdvice 在现代 Web 应用开发中扮演着不可替代的角色,深入理解其原理和应用是每个 Spring 开发者必备的核心能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值