Spring Boot统一功能处理深度解析

第一章:为什么需要统一功能处理?

想象你正在开发一个电商系统,包含用户管理、商品管理、订单管理等模块。每个模块都需要:

  1. 用户身份验证
  2. 操作日志记录
  3. 异常统一处理
  4. 数据格式标准化

如果每个模块都单独实现这些功能:

java 复制代码
// 用户模块
@PostMapping("/users")
public User createUser(@RequestBody User user) {
    try {
        // 1. 验证token
        // 2. 记录日志
        // 3. 业务处理
        // 4. 统一返回格式
    } catch (Exception e) {
        // 5. 异常处理
    }
}

// 商品模块
@PostMapping("/products")
public Product createProduct(@RequestBody Product product) {
    try {
        // 重复步骤1-5...
    } catch (Exception e) {
        // ...
    }
}

问题暴露

  • 代码重复率高(DRY原则被破坏)
  • 维护困难(修改需多处调整)
  • 系统一致性差(不同开发者实现方式不同)

第二章:Spring Boot统一处理四大核心组件

2.1 拦截器(Interceptor) - 请求的"安检门"

作用:在请求到达Controller前/后执行通用逻辑

java 复制代码
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) {
        // 1. 从请求头获取Token(就像门卫检查你的门禁卡)
        String token = request.getHeader("Authorization");
        
        // 2. 验证Token是否有效(门卫刷卡机验证)
        if (!validateToken(token)) {
            // 3. 无效则拒绝进入(设置401状态码)
            response.setStatus(401);
            return false; // 中断请求
        }
        return true; // 允许进入
    }
    
    // 验证Token的方法(门卫的验证设备)
    private boolean validateToken(String token) {
        // 实际验证逻辑(这里简化为非空检查)
        return token != null && !token.isEmpty();
    }
}

通俗解释

  • 这个类就像小区的门卫,检查每个进入的人(请求)
  • preHandle方法:在业主回家前检查门禁卡(Token)
  • 如果门禁卡无效(validateToken返回false),门卫会拒绝进入(返回401状态码)
  • 如果有效,就放行(return true)

配置方式

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 给门卫分配工作区域
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/api/**")   // 保护所有/api路径
                .excludePathPatterns("/api/login"); // 但登录入口不需要检查
    }
}

通俗解释

  • 这相当于给门卫划定工作范围:
    • /api/**:需要检查的所有区域
    • /api/login:特殊通道(登录入口),不需要检查
2.2 过滤器(Filter) - 请求的"净化器"

作用:处理HTTP请求/响应的原始数据

java 复制代码
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        // 1. 记录请求开始时间(水电表开始计数)
        long startTime = System.currentTimeMillis();
        
        // 2. 继续处理请求(让水流/电流继续)
        chain.doFilter(request, response);
        
        // 3. 计算耗时(计算水电用量)
        long duration = System.currentTimeMillis() - startTime;
        
        // 4. 记录日志(生成水电账单)
        System.out.println("请求耗时: " + duration + "ms");
    }
}
  • 这个过滤器就像水电表:
    1. 请求开始时记录时间(开水龙头)
    2. chain.doFilter让请求继续处理(水流)
    3. 请求结束后计算耗时(关水龙头,计算用水量)
    4. 记录日志(生成水电账单)

与拦截器区别

特性 过滤器(Filter) 拦截器(Interceptor)
作用范围 Servlet规范 Spring MVC特有
依赖 不依赖Spring容器 依赖Spring容器
获取信息 原始HTTP请求/响应 HandlerMethod信息
执行顺序 最先执行 在DispatcherServlet后执行
2.3 切面(AOP) - 功能的"手术刀"

作用:在方法执行前后插入通用逻辑

java 复制代码
@Aspect
@Component
public class ServiceMonitorAspect {
    
    // 监控Service层方法
    @Around("execution(* com.example..service.*.*(..))")
    public Object monitorService(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return pjp.proceed(); // 执行目标方法
        } finally {
            long duration = System.currentTimeMillis() - start;
            // 记录慢查询
            if (duration > 500) {
                log.warn("慢方法: {} 耗时: {}ms", 
                         pjp.getSignature(), duration);
            }
        }
    }
}
2.4 控制器增强(@ControllerAdvice) - 全局的"管理员"

作用:统一处理控制器异常和返回格式

java 复制代码
@ControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResponseResult<Void> handleBusinessEx(BusinessException e) {
        return ResponseResult.error(e.getCode(), e.getMessage());
    }
    
    // 处理所有未捕获异常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return ResponseResult.error(500, "系统繁忙");
    }
}

第三章:统一功能处理实战案例

3.1 统一响应格式
java 复制代码
// 标准响应体
public class ResponseResult<T> {
    private int code;
    private String msg;
    private T data;
    
    // 成功响应
    public static <T> ResponseResult<T> success(T data) {
        return new ResponseResult<>(200, "成功", data);
    }
    
    // 错误响应
    public static <T> ResponseResult<T> error(int code, String msg) {
        return new ResponseResult<>(code, msg, null);
    }
}

// 控制器统一返回
@RestController
public class UserController {
    @GetMapping("/users/{id}")
    public ResponseResult<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseResult.success(user);
    }
}
3.2 统一异常处理
java 复制代码
@ControllerAdvice // 1. 声明这是全局异常处理器
public class GlobalExceptionHandler {
    
    // 2. 处理业务异常(如订单处理失败)
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResponseResult<Void> handleBusinessEx(BusinessException e) {
        // 返回标准错误格式
        return ResponseResult.error(e.getCode(), e.getMessage());
    }
    
    // 3. 处理所有未预料异常(系统崩溃)
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult<Void> handleException(Exception e) {
        // 记录错误日志(就像应急系统记录事故)
        e.printStackTrace();
        // 返回友好提示
        return ResponseResult.error(500, "系统繁忙,请稍后再试");
    }
}
  • @ControllerAdvice:这是整个小区的应急中心
  • @ExceptionHandler:不同类型的应急处理小组
    • BusinessException:处理业务问题(如订单错误)
    • Exception:处理所有未预料的问题(系统崩溃)
  • 当发生问题时,系统会自动调用对应的方法处理
3.3 统一日志记录
java 复制代码
@Aspect
@Component
public class ControllerLogAspect {
    
    @Around("@within(org.springframework.web.bind.annotation.RestController)")
    public Object logController(ProceedingJoinPoint pjp) throws Throwable {
        // 获取请求信息
        HttpServletRequest request = 
            ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
            .getRequest();
        
        // 记录请求日志
        log.info("请求开始 => URI: {}, 参数: {}", 
                 request.getRequestURI(), 
                 Arrays.toString(pjp.getArgs()));
        
        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed();
            // 记录响应日志
            log.info("请求完成 <= URI: {}, 耗时: {}ms", 
                     request.getRequestURI(), 
                     System.currentTimeMillis() - start);
            return result;
        } catch (Exception e) {
            // 记录异常日志
            log.error("请求异常 <= URI: {}, 错误: {}", 
                      request.getRequestURI(), e.getMessage());
            throw e;
        }
    }
}
3.4 统一身份认证
java 复制代码
public class JwtAuthInterceptor implements HandlerInterceptor {
    
    @Autowired
    private JwtTokenService tokenService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) {
        // 1. 获取Token
        String token = request.getHeader("Authorization");
        if (StringUtils.isEmpty(token)) {
            sendError(response, 401, "未提供认证信息");
            return false;
        }
        
        // 2. 验证Token
        Claims claims = tokenService.parseToken(token);
        if (claims == null) {
            sendError(response, 401, "无效的Token");
            return false;
        }
        
        // 3. 存储用户信息
        UserContext.setCurrentUser(claims.getSubject());
        return true;
    }
    
    private void sendError(HttpServletResponse response, int status, String msg) {
        response.setStatus(status);
        response.setContentType("application/json");
        try {
            response.getWriter().write(
                new ResponseResult<>(status, msg).toString()
            );
        } catch (IOException e) {
            log.error("响应写入失败", e);
        }
    }
}

第四章:高级应用场景

4.1 接口限流(Rate Limiting)
java 复制代码
@Aspect
@Component
public class RateLimitAspect {
    
    private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
    
    @Around("@annotation(rateLimit)")
    public Object rateLimit(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {
        String key = getRateLimitKey(pjp);
        RateLimiter limiter = limiters.computeIfAbsent(key, 
            k -> RateLimiter.create(rateLimit.value()));
        
        if (limiter.tryAcquire()) {
            return pjp.proceed();
        } else {
            throw new BusinessException(429, "请求过于频繁");
        }
    }
    
    private String getRateLimitKey(ProceedingJoinPoint pjp) {
        // 根据方法+IP生成唯一key
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        HttpServletRequest request = 
            ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
            .getRequest();
        return signature.getMethod().getName() + ":" + request.getRemoteAddr();
    }
}

// 使用注解
@GetMapping("/api/data")
@RateLimit(value = 10) // 每秒10次
public ResponseResult<Data> getData() {
    // ...
}
4.2 多租户数据隔离
java 复制代码
public class TenantInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) {
        // 从请求头获取租户ID
        String tenantId = request.getHeader("X-Tenant-ID");
        if (StringUtils.isNotBlank(tenantId)) {
            TenantContext.setCurrentTenant(tenantId);
        }
        return true;
    }
}

// 在MyBatis拦截器中应用
@Intercepts({@Signature(type = Executor.class, method = "query", ...)})
public class TenantInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 自动添加租户过滤条件
        String tenantId = TenantContext.getCurrentTenant();
        if (tenantId != null) {
            MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
            Object parameter = invocation.getArgs()[1];
            // 修改SQL添加 tenant_id = #{tenantId}
        }
        return invocation.proceed();
    }
}
4.3 API版本控制
java 复制代码
public class ApiVersionInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) {
        // 从URL路径获取版本号
        String path = request.getRequestURI();
        Matcher matcher = Pattern.compile("/v(\\d+)/").matcher(path);
        if (matcher.find()) {
            int version = Integer.parseInt(matcher.group(1));
            ApiVersionContext.setVersion(version);
        }
        return true;
    }
}

// 控制器根据版本路由
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping
    @ApiVersion(1) // v1版本
    public ResponseResult<List<User>> getUsersV1() {
        // 旧版逻辑
    }
    
    @GetMapping
    @ApiVersion(2) // v2版本
    public ResponseResult<List<UserDto>> getUsersV2() {
        // 新版逻辑
    }
}

第五章:性能优化与最佳实践

5.1 组件执行顺序优化
复制代码
请求进入

Filter-Interceptor-preHandle-Controller-Interceptor-postHandle-Filter-after-Response

优化策略

  1. 过滤器优先处理原始数据(如请求体缓存)
  2. 拦截器处理业务相关逻辑(如认证、日志)
  3. 切面处理具体方法逻辑(如性能监控)
  4. @ControllerAdvice最后处理异常和响应
5.2 避免的陷阱
  1. 循环依赖问题

java 复制代码
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Autowired
    private AuthService authService; // 可能导致循环依赖
}

解决方案 :使用@Lazy延迟注入
3.

java 复制代码
@Lazy
@Autowired
private AuthService authService;

线程安全问题
4.

java 复制代码
public class UserContext {
    private static final ThreadLocal<User> currentUser = new ThreadLocal<>();
}

性能热点
5.

java 复制代码
// 避免在拦截器/过滤器中执行耗时操作
public boolean preHandle(...) {
    // 错误:执行数据库查询
    User user = userRepository.findById(userId);
}
5.3 最佳实践总结
  1. 职责分离原则

    • 过滤器:处理原始HTTP请求/响应
    • 拦截器:处理业务相关前置/后置逻辑
    • 切面:处理具体方法逻辑
    • 控制器增强:统一异常和响应处理
  2. 配置顺序原则

java 复制代码
@Override
public void addInterceptors(InterceptorRegistry registry) {
    // 1. 认证拦截器(最先执行)
    registry.addInterceptor(authInterceptor);
    
    // 2. 日志拦截器
    registry.addInterceptor(logInterceptor);
    
    // 3. 其他业务拦截器
}

性能监控指标
9.

java 复制代码
// 使用Micrometer监控
@Autowired
private MeterRegistry meterRegistry;

public void afterCompletion(...) {
    meterRegistry.counter("api.requests", 
        "uri", request.getRequestURI(),
        "status", String.valueOf(response.getStatus())
    ).increment();
}

第六章:综合实战 - 电商系统统一处理

6.1 系统架构图

6.2 核心配置代码

java 复制代码
// 网关统一配置
@Configuration
public class GatewayConfig {
    
    @Bean
    public GlobalFilter customFilter() {
        return (exchange, chain) -> {
            // 1. 统一添加请求ID
            ServerHttpRequest request = exchange.getRequest().mutate()
                .header("X-Request-ID", UUID.randomUUID().toString())
                .build();
            return chain.filter(exchange.mutate().request(request).build());
        };
    }
}

// 微服务统一配置
@Configuration
public class ServiceConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TenantInterceptor());
        registry.addInterceptor(new AuthInterceptor());
    }
    
    @Bean
    public FilterRegistrationBean<LoggingFilter> loggingFilter() {
        FilterRegistrationBean<LoggingFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new LoggingFilter());
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}
6.3 业务服务示例
java 复制代码
@RestController
@RequestMapping("/orders")
public class OrderController {
    
    @PostMapping
    public ResponseResult<Order> createOrder(@Valid @RequestBody OrderCreateDTO dto) {
        // 无需处理认证、日志、异常等
        Order order = orderService.createOrder(dto);
        return
相关推荐
BillKu1 小时前
Java + Spring Boot + Mybatis 实现批量插入
java·spring boot·mybatis
YuTaoShao1 小时前
Java八股文——集合「Map篇」
java
有梦想的攻城狮3 小时前
maven中的maven-antrun-plugin插件详解
java·maven·插件·antrun
恸流失6 小时前
DJango项目
后端·python·django
硅的褶皱7 小时前
对比分析LinkedBlockingQueue和SynchronousQueue
java·并发编程
MoFe17 小时前
【.net core】天地图坐标转换为高德地图坐标(WGS84 坐标转 GCJ02 坐标)
java·前端·.netcore
季鸢7 小时前
Java设计模式之观察者模式详解
java·观察者模式·设计模式
Fanxt_Ja8 小时前
【JVM】三色标记法原理
java·开发语言·jvm·算法
Mr Aokey8 小时前
Spring MVC参数绑定终极手册:单&多参/对象/集合/JSON/文件上传精讲
java·后端·spring
14L9 小时前
互联网大厂Java面试:从Spring Cloud到Kafka的技术考察
spring boot·redis·spring cloud·kafka·jwt·oauth2·java面试