Spring Boot 中 Filter、Interceptor 和 AOP 的全面对比与应用场景
Spring Boot 中 Filter、Interceptor 和 AOP 的全面对比与应用场景
Spring Boot 中Filter(过滤器)、Interceptor(拦截器)、AOP的区别、执行顺序、适用场景。
1. 三者一句话定位
- Filter(过滤器)
→Servlet 规范,在 Tomcat 容器层工作,最早执行,能拦截所有请求(静态资源、Servlet、Controller)。
- HandlerInterceptor(拦截器)
→Spring MVC 组件,在 Spring 容器内工作,只拦截进入 Controller 的请求。
- AOP(面向切面)
→Spring 核心功能,不局限于 Web,可拦截任意方法(Service、Dao、Controller 等)。
2. 执行顺序(最重要)
请求进来时顺序:
- Filter → 2. Interceptor → 3. AOP → Controller
返回时顺序:
Controller → AOP → Interceptor → Filter
简单记:Filter 最外,AOP 最里。
3. 详细对比表
| 对比项 | Filter(过滤器) | Interceptor(拦截器) | AOP |
|---|---|---|---|
| 所属规范 | Servlet 规范 | Spring MVC | Spring 核心 |
| 作用范围 | 所有 Web 请求 | 只拦截 Controller 请求 | 任意 Spring Bean 方法 |
| 能否获取 Bean | 不能直接注入 Spring Bean | 可以 | 可以 |
| 能否获取请求 | 可以(request/response) | 可以 | 不能直接获取,需依赖 RequestContextHolder |
| 能否获取方法 | 不能 | 可以(HandlerMethod) | 可以(切点、方法签名) |
| 适用场景 | 编码、跨域、限流、请求头过滤 | 登录校验、日志、权限 | 日志、事务、缓存、通用增强 |
| 触发时机 | 最早 | 中间 | 最晚(靠近方法) |
4. 各自核心用法(极简)
① Filter(过滤器)
实现javax.servlet.Filter
@Component public class MyFilter implements Filter { @Override public void doFilter(...) { // 请求前 chain.doFilter(request, response); // 响应后 } }② Interceptor(拦截器)
实现HandlerInterceptor
@Component public class MyInterceptor implements HandlerInterceptor { // 进入Controller前 @Override public boolean preHandle(...) throws Exception { return true; } // Controller执行后 @Override public void postHandle(...) {} // 视图渲染后 @Override public void afterCompletion(...) {} }③ AOP
使用@Aspect+ 切点表达式
@Aspect @Component public class MyAop { @Before("execution(* com.xxx.controller.*.*(..))") public void before() { // 方法执行前 } }5. 怎么选择?(最实用)
要过滤所有请求(静态资源、跨域、编码)→Filter
要拦截Controller、做登录/权限→Interceptor
要通用方法增强(日志、事务、缓存)→AOP
6. 一句话总结
Filter:容器层守门员,拦所有请求
Interceptor:MVC守门员,拦Controller
AOP:方法级增强,拦任意方法
以下是可直接运行的 Spring Boot 完整示例代码,涵盖 Filter、Interceptor、AOP 三种组件的完整实现、配置及测试场景:
7. 完整可运行示例代码
7.1 项目依赖(pom.xml)
核心依赖为 Spring Boot Web,无需额外引入其他依赖(AOP 已包含在 Spring 核心依赖中):
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.15</version><!-- 稳定版本,可根据需求调整 --><relativePath/></parent><dependencies><!-- Spring Boot Web 核心依赖(包含 Servlet、Spring MVC) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>7.2 核心组件实现
7.2.1 Filter 实现与配置
功能:记录请求进入时间,拦截所有 Web 请求(包括静态资源)
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; // 注解方式配置:拦截所有路径(/*),过滤器名称为 MyFilter @WebFilter(urlPatterns = "/*", filterName = "MyFilter") public class MyFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(MyFilter.class); // 过滤器初始化(项目启动时执行) @Override public void init(FilterConfig filterConfig) throws ServletException { logger.info("MyFilter 初始化"); } // 核心过滤逻辑(每次请求都会执行) @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 1. 请求前处理 HttpServletRequest request = (HttpServletRequest) servletRequest; String requestUrl = request.getRequestURL().toString(); long startTime = new Date().getTime(); logger.info("MyFilter 拦截请求:{},进入时间:{}", requestUrl, startTime); // 2. 放行请求(继续向下执行,进入 Interceptor) filterChain.doFilter(servletRequest, servletResponse); // 3. 响应后处理 long endTime = new Date().getTime(); logger.info("MyFilter 完成响应:{},耗时:{}ms", requestUrl, (endTime - startTime)); } // 过滤器销毁(项目停止时执行) @Override public void destroy() { logger.info("MyFilter 销毁"); } }Filter 启用配置(主启动类添加注解):
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; // 扫描 Servlet 组件(@WebFilter、@WebServlet 等) @ServletComponentScan @SpringBootApplication public class FilterInterceptorAopApplication { public static void main(String[] args) { SpringApplication.run(FilterInterceptorAopApplication.class, args); } }7.2.2 Interceptor 实现与配置
功能:登录校验(模拟),只拦截 Controller 请求
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class MyInterceptor implements HandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class); // 1. 进入 Controller 前执行(核心校验逻辑) @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.info("MyInterceptor preHandle:进入 Controller 前校验"); // 模拟登录校验:从 Session 中获取用户信息,无则拦截 HttpSession session = request.getSession(); Object user = session.getAttribute("loginUser"); if (user == null) { logger.warn("用户未登录,拦截请求:{}", request.getRequestURL()); // 未登录则重定向到登录页(或返回 401) response.sendRedirect("/login"); return false; // 拦截请求,不进入 Controller } return true; // 放行请求,进入 Controller } // 2. Controller 执行后、视图渲染前执行 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.info("MyInterceptor postHandle:Controller 执行完成,准备渲染视图"); } // 3. 视图渲染后执行(整个请求完成) @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.info("MyInterceptor afterCompletion:请求完全完成"); } }Interceptor 注册配置(需手动注册到 Spring 容器):
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; // 配置类:注册 Interceptor @Configuration public class WebMvcConfig implements WebMvcConfigurer { // 注册自定义拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/api/**") // 拦截 /api 下所有请求(只拦截 Controller 相关请求) .excludePathPatterns("/login"); // 排除登录接口,不拦截 } }7.2.3 AOP 实现
功能:记录 Service 层方法执行日志(通用方法增强)
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.aspectj.lang.annotation.Aspect; import java.lang.reflect.Method; // 标识为切面类 @Aspect // 交给 Spring 管理 @Component public class MyAop { private static final Logger logger = LoggerFactory.getLogger(MyAop.class); private long startTime; // 切入点:拦截 com.example.service 包下所有类的所有方法 @Pointcut("execution(* com.example.service.*.*(..))") public void servicePointCut() {} // 方法执行前增强 @Before("servicePointCut()") public void beforeMethod(JoinPoint joinPoint) { startTime = System.currentTimeMillis(); // 获取方法信息 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); String className = joinPoint.getTarget().getClass().getName(); logger.info("MyAop 方法执行前:类名={},方法名={}", className, method.getName()); } // 方法执行后增强 @After("servicePointCut()") public void afterMethod(JoinPoint joinPoint) { long endTime = System.currentTimeMillis(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); logger.info("MyAop 方法执行后:方法名={},耗时={}ms", method.getName(), (endTime - startTime)); } }7.3 测试场景(Controller + Service)
7.3.1 测试 Service
import org.springframework.stereotype.Service; @Service public class TestService { // 测试方法,会被 AOP 拦截 public String testMethod(String param) { return "Service 处理完成,参数:" + param; } }7.3.2 测试 Controller
import com.example.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; @RestController public class TestController { @Autowired private TestService testService; // 登录接口(不被 Interceptor 拦截) @GetMapping("/login") public String login(HttpSession session) { // 模拟登录:向 Session 存入用户信息 session.setAttribute("loginUser", "testUser"); return "登录成功"; } // 测试接口(被 Interceptor 拦截,调用 Service 被 AOP 拦截) @GetMapping("/api/test") public String test(@RequestParam String param) { return testService.testMethod(param); } }7.4 运行测试与预期结果
7.4.1 测试步骤
启动 Spring Boot 项目,观察日志:MyFilter 初始化
访问登录接口:http://localhost:8080/login,返回「登录成功」
访问测试接口:http://localhost:8080/api/test?param=hello,观察日志输出顺序
7.4.2 预期日志顺序(对应执行顺序)
// 1. Filter 拦截请求 MyFilter 拦截请求:http://localhost:8080/api/test,进入时间:xxx // 2. Interceptor 进入 Controller 前校验 MyInterceptor preHandle:进入 Controller 前校验 // 3. AOP 拦截 Service 方法执行前 MyAop 方法执行前:类名=com.example.service.TestService,方法名=testMethod // 4. Service 方法执行(业务逻辑) // 5. AOP 拦截 Service 方法执行后 MyAop 方法执行后:方法名=testMethod,耗时=xxms // 6. Interceptor Controller 执行完成 MyInterceptor postHandle:Controller 执行完成,准备渲染视图 // 7. Interceptor 请求完全完成 MyInterceptor afterCompletion:请求完全完成 // 8. Filter 响应完成 MyFilter 完成响应:http://localhost:8080/api/test,耗时=xxms7.5 关键说明
包路径说明:示例中包路径为
com.example,实际开发中需替换为自己的项目包路径依赖版本:示例使用 Spring Boot 2.7.15(稳定版),若使用 3.x 版本,需注意 Servlet API 从 javax 迁移为 jakarta,代码需对应调整(如
javax.servlet.Filter→jakarta.servlet.Filter)扩展场景:可根据需求修改 Filter 拦截路径、Interceptor 校验逻辑、AOP 切入点(如拦截 Controller 或 Dao 层方法)
