在 Spring Boot 应用程序开发中,Filter(过滤器)、Interceptor(拦截器)和 AOP(面向切面编程)是三种常见的横切关注点实现方式。
它们各有特点和适用场景,正确的选择和使用这些技术对于构建高质量的应用程序至关重要。
一、基本概念与执行顺序
1. Filter(过滤器)
Filter 是 Servlet 规范中定义的组件,位于 Web 容器中,在请求到达 Servlet 之前和响应返回客户端之前进行处理。
@Component
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
log.info("请求URL: {}", req.getRequestURI());
// 继续执行过滤器链
chain.doFilter(request, response);
log.info("响应已完成");
}
}
2. Interceptor(拦截器)
Interceptor 是 Spring MVC 框架提供的组件,位于 DispatcherServlet 之后,Controller 处理之前。
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 在Controller方法执行前调用
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
// 在Controller方法执行后,视图渲染前调用
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 在整个请求完成后调用
}
}
3. AOP(面向切面编程)
AOP 是 Spring 框架提供的一种编程范式,可以在不修改源代码的情况下为方法添加功能。
@Aspect
@Component
public class PerformanceAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
log.info("{} 执行耗时 {} ms", joinPoint.getSignature(), executionTime);
return result;
}
}
执行顺序
请求处理的顺序为:Filter -> Interceptor -> AOP -> Controller -> AOP -> Interceptor -> Filter
二、使用场景对比
特性 |
Filter |
Interceptor |
AOP |
作用范围 |
所有请求 |
匹配的URL请求 |
指定的方法 |
实现层面 |
Servlet容器 |
Spring MVC |
Spring容器 |
能否获取方法及类信息 |
否 |
是 |
是 |
应用场景 |
请求过滤、字符编码等 |
用户认证、日志记录等 |
事务、日志、权限等 |
三、使用场景分析
1. Filter 适用场景
请求/响应预处理:如字符编码设置、CORS跨域处理 请求内容转换:如请求体解析、加解密 身份验证:如JWT令牌验证 日志记录:记录所有请求的访问日志 敏感信息过滤:过滤敏感词汇
@Component
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
}
2. Interceptor 适用场景
用户认证:检查用户是否已登录 权限控制:检查用户是否有权限访问特定资源 性能监控:监控控制器方法执行时间 日志记录:记录请求处理过程中的详细信息 国际化处理:根据请求设置语言环境
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequiresPermission annotation = handlerMethod.getMethodAnnotation(RequiresPermission.class);
if (annotation != null) {
String requiredPermission = annotation.value();
// 检查用户权限
if (!hasPermission(request, requiredPermission)) {
response.setStatus(HttpStatus.FORBIDDEN.value());
return false;
}
}
return true;
}
private boolean hasPermission(HttpServletRequest request, String permission) {
// 权限检查逻辑
return true;
}
}
3. AOP 适用场景
事务管理:方法执行前开启事务,执行后提交或回滚 方法性能监控:记录方法执行时间 日志记录:记录方法调用的参数和返回值 缓存处理:方法执行前查询缓存,执行后更新缓存 异常处理:统一处理特定异常
@Aspect
@Component
public class CacheAspect {
@Autowired
private CacheManager cacheManager;
@Around("@annotation(com.example.annotation.Cacheable)")
public Object cache(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Cacheable cacheable = method.getAnnotation(Cacheable.class);
String cacheKey = generateCacheKey(joinPoint, cacheable);
Object cachedValue = cacheManager.get(cacheKey);
if (cachedValue != null) {
return cachedValue;
}
Object result = joinPoint.proceed();
cacheManager.put(cacheKey, result);
return result;
}
private String generateCacheKey(ProceedingJoinPoint joinPoint, Cacheable cacheable) {
// 生成缓存键
return cacheable.value();
}
}
四、选型指南
何时选择 Filter:
- 需要处理所有的 HTTP 请求
- 需要在请求到达控制器之前进行预处理
- 处理与 Servlet 规范相关的功能
- 需要修改请求或响应对象
- 实现框架无关的功能
何时选择 Interceptor:
- 需要访问 Spring MVC 特定的功能
- 需要访问控制器的上下文
- 只需拦截匹配的 URL 请求
- 需要灵活的请求拦截配置
- 需要多个处理阶段(前置、后置、完成后)
何时选择 AOP:
- 需要拦截特定方法的执行
- 需要处理业务逻辑层的横切关注点
- 需要访问方法的参数和返回值
- 需要更细粒度的控制
- 非 Web 层的功能增强
五、最佳实践
1. 组合使用
在实际项目中,这三种技术往往会组合使用:
Filter:处理通用的 Web 请求处理,如编码设置、CORS 配置 Interceptor:处理与用户认证、授权相关的功能 AOP:处理业务层面的横切关注点,如日志、性能监控、事务等
2. 性能考虑
- Filter 和 Interceptor 主要用于 Web 层,每个请求只会经过一次
- AOP 可能会作用于多个方法,影响更多的调用点
- 在高并发场景下,应尽量减少 AOP 切面的数量和复杂度
3. 代码组织
将不同横切关注点的实现分离:
- 认证授权相关的逻辑放在 Interceptor 中
- 日志、监控等通用功能可以使用 AOP 实现
- 请求预处理、编码设置等通用功能使用 Filter 实现
六、总结
选择合适的技术取决于具体需求、性能考虑和团队熟悉度。在实际应用中,合理组合使用这三种技术可以构建更加模块化、可维护的应用程序。
对于 Spring Boot 应用程序,推荐遵循"责任分离"原则,根据横切关注点的性质选择最合适的实现方式,让代码结构更加清晰,逻辑更加分明。