过滤器,拦截器,AOP之间差异
一、引言
在Spring Boot项目中,我们经常会使用到过滤器、拦截器和AOP,来实现一个切面的功能,那么他们之间的差异有哪些,在某个场景下我们应该选择哪个去使用呢?
二、客户端请求流程
当客户端发送一个请求时,执行流程如下:
- 客户端发送请求。
- 请求首先经过过滤器链中的过滤器。每个过滤器可以在
doFilter
方法中对请求进行处理,然后调用chain.doFilter
方法继续执行下一个过滤器或目标资源。 - 经过过滤器处理后,请求进入拦截器。拦截器可以在请求处理之前或之后执行一些逻辑,例如验证用户权限、记录日志等。
- 经过拦截器处理后,请求进入AOP切面。AOP切面中的通知定义了在何时、何地执行额外的代码,例如在方法执行前后、抛出异常时等。
- 最终请求到达Controller方法,AOP切面的通知在方法执行前后执行额外的代码。
- Controller方法处理请求并生成响应。
- 响应经过AOP切面的通知,拦截器和过滤器,每个组件都可以在处理过程中对响应进行处理。
- 最终响应返回给客户端。
接下来,我们来分别讲一下过滤器、拦截器和AOP。
三、过滤器
-
简介
过滤器(Filter)是Servlet规范中的一种组件,它可以拦截客户端请求和目标资源的响应,对它们进行处理和过滤。过滤器可以用于在请求处理之前或响应返回之前执行一些逻辑,例如验证用户权限、记录请求日志、对请求进行安全过滤、设置编码、过滤敏感词汇等。
-
代码实现
定义过滤器,实现Filter接口重写过滤方法
@Component public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 过滤器初始化逻辑 Filter.super.init(filterConfig); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 在请求处理之前执行的逻辑 System.out.println("请求前的过滤"); // 调用链中的下一个过滤器,如果没有则执行目标资源 filterChain.doFilter(servletRequest, servletResponse); // 在请求处理之后执行的逻辑 System.out.println("请求后的过滤"); } @Override public void destroy() { // 过滤器销毁逻辑 Filter.super.destroy(); } }
定义一个Controller方法
@RestController @RequestMapping("/api/activity") public class MyController { @GetMapping("/request") public R request() { System.out.println("执行了一个请求"); return R.ok("执行了一个请求"); } }
测试请求结果
四、拦截器
-
简介
拦截器(Interceptor)是Spring MVC框架提供的一种机制,用于在请求处理的不同阶段执行额外的逻辑。拦截器可以在请求处理前、请求处理后以及请求处理异常时执行一些操作,例如日志记录、权限验证、性能监控等。拦截器可以灵活地应用于Spring MVC框架中,对请求进行拦截和处理。
-
拦截器与过滤器的区别
- 拦截器是AOP思想的具体应用(一个横切面,直接切进请求响应中去)。
- 拦截器是spring MVC特有的。
- 拦截器只会拦截访问控制器的方法,如果访问静态资源如:.jsp/html/css/image/js 时,它不会去拦截,而Filter过滤器无论什么都会去拦截。
-
代码实现
定义一个拦截器,实现HandlerInterceptor接口中的拦截方法
public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在请求处理之前执行的逻辑 System.out.println("请求前的拦截"); return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在请求处理之后,视图被渲染之前执行的逻辑 System.out.println("请求后渲染前的拦截"); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 在请求处理完成之后执行的逻辑 System.out.println("请求后的拦截"); HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
编写配置类,实现WebMvcConfigurer接口中的添加拦截器addInterceptors方法
@Configuration public class MyMvcConfig implements WebMvcConfigurer { @Bean public MyInterceptor myInterceptor() { return new MyInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor()) .addPathPatterns("/api/**") //拦截所有api请求 .excludePathPatterns("/api/user/login");//放行其中的login } }
Controller方法还是原来那个
@RestController @RequestMapping("/api/activity") public class MyController { @GetMapping("/request") public R request() { System.out.println("执行了一个请求"); return R.ok("执行了一个请求"); } }
测试请求结果
五、AOP
-
简介
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它的目的是通过将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,使得这些关注点可以被模块化、重用和集中化管理。AOP可以帮助我们实现日志记录、事务管理、安全控制、性能统计等功能,而无需修改核心业务逻辑的代码。在Java领域,Spring框架提供了强大的AOP支持。
-
AOP的核心概念
- 切面(Aspect):切面是横切关注点的模块化,它包含了一组通知(advice)和切点(pointcut)。通知定义了在何时、何地执行额外的逻辑,而切点定义了在何处执行额外的逻辑。
- 通知(Advice):通知是在切面的特定连接点(join point)上执行的额外的逻辑。通知的类型包括前置通知(before advice)、后置通知(after advice)、返回通知(after-returning advice)、异常通知(after-throwing advice)和环绕通知(around advice)。
- 连接点(Join Point):连接点是在应用执行过程中能够插入切面的点,比如方法的调用、异常的抛出等。
- 切点(Pointcut):切点是连接点的集合,它定义了切面在何处执行额外的逻辑。切点使用表达式来匹配连接点。
- 引入(Introduction):引入允许我们向现有的类添加新的方法或属性。
-
代码实现
定义切面,定义前需要导入spring-boot-starter-aop依赖
@Aspect @Component public class MyAop { @Before("execution(public * com.wnhz.ssc.*.controller.*.*(..))") public void before() { System.out.println("aop切面before"); } @After("execution(public * com.wnhz.ssc.*.controller.*.*(..))") public void after() { System.out.println("aop切面after"); } @AfterReturning("execution(public * com.wnhz.ssc.*.controller.*.*(..))") public void afterReturning() { System.out.println("aop切面afterReturning"); } @AfterThrowing("execution(public * com.wnhz.ssc.*.controller.*.*(..))") public void afterThrowing() { System.out.println("aop切面afterThrowing"); } /*@Around("execution(public * com.wnhz.ssc.*.controller.*.*(..))") public Object around(ProceedingJoinPoint proceedingJoinPoint) { Object obj; System.out.println("around before"); try { obj = proceedingJoinPoint.proceed(); System.out.println("around after returning"); } catch (Throwable e) { System.out.println("around after throwing"); throw new RuntimeException(e); } finally { System.out.println("around after"); } return obj; }*/ }
Controller方法还是原来那个
@RestController @RequestMapping("/api/activity") public class MyController { @GetMapping("/request") public R request() { System.out.println("执行了一个请求"); return R.ok("执行了一个请求"); } }
测试请求结果
这样的话,我们就验证了刚开始给出的客户端请求流程里三者之间执行的顺序了:
用户请求——>过滤器——>拦截器——>aop切面——>Controller方法——>aop切面——>拦截器——>过滤器——>返回给用户
六、过滤器,拦截器,AOP之间差异小结
-
运行环境:
- 过滤器(Filter):基于Servlet规范,作用于Servlet容器中的请求和响应。
- 拦截器(Interceptor):基于Spring MVC框架,作用于Spring MVC中的请求和响应。
- AOP(Aspect Oriented Programming):基于Spring框架,作用于整个应用程序中的对象或方法。
-
作用对象
-
过滤器(Filter):Filter过滤器不只是拦截访问控制器的方法,还可以拦截静态资源
-
拦截器(Interceptor):拦截器只会拦截访问控制器的方法,如果访问静态资源如:.jsp/html/css/image/js 时,它不会去拦截
-
AOP(Aspect Oriented Programming):作用对象更加抽象和广泛,不仅局限于拦截请求和访问静态资源,而是通过在连接点上执行额外的逻辑,实现对横切关注点的模块化和重用。
-
-
触发时机:
- 过滤器(Filter):在请求进入容器之前和响应返回客户端之前执行。
- 拦截器(Interceptor):在请求处理之前和之后执行。
- AOP(Aspect Oriented Programming):在方法调用前、后或异常时执行。
-
使用场景:
- 过滤器(Filter):适用于对请求和响应进行过滤、处理和转换,如字符编码、安全过滤、日志记录等。
- 拦截器(Interceptor):适用于在请求处理前、后和完成后进行拦截和处理,如权限验证、性能统计、日志记录等。
- AOP(Aspect Oriented Programming):适用于实现横切关注点的功能,如事务管理、安全控制、日志记录等。