Java 拦截器Interceptor详解

1、拦截器概念
先看一下web请求的流程。
(1)、当浏览器发送一个请求时,请求到达tomcat容器,tomcat容器会区分静态还是动态资源。
(2)、动态请求会先经过过滤器链filter,直到全部过滤完成之后,会达到spring容器。
(3)、请求达到spring容器后,会经过中央处理器DispatcherServlet进行调度,请求转给指定的控制器Handler进行处理。
(4)、如果给控制器Handler注册了拦截器Interceptor,会先经过拦截器进行处理。
(5)、拦截器放行后,执行控制器的业务,在按照进入相反的路径最终返回给浏览器。
在这里插入图片描述
springMvc的具体流程图
在这里插入图片描述
拦截器的概念:
拦截器Interceptor是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。

2、拦截器实现原理
拦截器实现主要基于两个原理:AOP(动态代理)和责任链模式
AOP:是面向切面的编程的方式,可以在不改变源代码的基础上,进行业务扩展。
责任链模式:类似过滤器链,可以有多个拦截处理,一个处理后放行,下一个拦截才能处理。

具体执行:
(1)、请求执行Handler之前,生成Action对象,在Action方法执行之前,校验是否有当前Action的拦截器,有的话先走拦截器处理。
Action可以理解为行为,就是Controller中的一个对外接口。Handler则为一个任务调度。
(2)、基于AOP,先生成目标Action对象的proxy代理对象,在执行代理方法前,先执行拦截器链的前置方法preHandle。之后会执行代理方法,以及拦截器的postHandle后置方法。当视图渲染完成后,会执行afterCompletion方法。
在这里插入图片描述
3、代码示例
(1)、编写拦截器类(需要实现HandlerInterceptor接口)

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class StudentInterceptor implements HandlerInterceptor{

    // 在业务处理器处理请求之前被调用(Controller之前)
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行了: StudentInterceptor的preHandle");

        return true;
    }

    // 在业务处理器处理请求完成之后,生成视图之前执行(controller执行完成,前端视图生成之前)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("执行了: StudentInterceptor的postHandle");
    }

    // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("执行了: StudentInterceptor的afterCompletion");
    }
}

(2)、注册拦截器(实现WebMvcConfigurer接口)

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfigure implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
       //静态资源请求的映射,如静态请求为/pages/**,则请求会在程序的类路径(通常是src/main/resources目录)下的/pages/目录中查找这些资源
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    // 注册拦截器,指定拦截和放行路径(先注册的拦截器会先执行)
     registry.addInterceptor(new StudentInterceptor()).addPathPatterns("/student","/student/*") .excludePathPatterns("/login", "/register");
        registry.addInterceptor(new TeacherInterceptor()).addPathPatterns("/student/**");
    }
}

(3)、在controller中正常写接口,可以测试拦截效果。

4、使用类解读
(1)、拦截器生明的方法
实现HandlerInterceptor或继承HandlerInterceptorAdapter,标识当前类试一个拦截器。
如果使用HandlerInterceptor,就需要覆写拦截器默认的三个方法。如果是继承HandlerInterceptorAdapter,则可以按照自己的需要去进行方法覆写,不用把三个方法都定义出来。HandlerInterceptorAdapter实现了HandlerInterceptor接口,提供了空实现的方法,所以你可以选择只覆盖自己关心的方法。
(2)、拦截器preHandle的参数
Object handler 被调用的Action对象,本质上是一个方法对象,对反射中的Method对象进行了再包装,可以基于反射获取相关信息
如:
HandlerMethod hm = (HandlerMethod)handler;
Method method = hm.getMethod();
String methodName = method .getName();//可以获取方法的名称
(3)、拦截器注册到WebMvc
WebMvcConfigurer(接口):用于自定义的Spring MVC配置,如拦截器、视图解析器、消息转换器等,而无需完全重写默认的Spring MVC配置。(推荐)
WebMvcConfigurerAdapter(抽象类):实现了WebMvcConfigurer接口,提供了默认的空配置,不过在java8中已经废弃,(不推荐使用)。
WebMvcConfigurationSupport(抽象类):提供了Spring MVC的默认配置,确实需要完全控制Spring MVC的配置时可以用。这样做可能会导致Spring Boot的自动配置失效,包括那些你可能依赖的自动配置。(特别不推荐)
(4)、ResourceHandlerRegistry
是Spring MVC中用于处理静态资源请求的重要组件,它使得开发者能够灵活地配置和管理静态资源的访问。
(5)、InterceptorRegistry
提供了一种方便的方式来注册和管理拦截器,以实现各种请求处理前后的逻辑操作。

5、与filter区别
(1)、归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术。
(2)、拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强。
(3)、拦截器可以对Action对象获取(获取到方法对象),进行反射等业务处理,过滤器则不行。

使用场景:
(1)、拦截器主要用于AOP(面向切面编程),即在方法执行前后进行相应的处理。典型的应用场景包括:
身份验证:检查用户是否登录或者是否有权限访问某个资源。
日志记录:记录请求参数、响应结果、请求时间等信息,方便后续的调试和分析。
事务处理:在业务方法执行前后,启动或提交事务,保证数据的完整性和一致性。
缓存控制:对请求进行缓存,提高系统性能和响应速度等。

(2)、过滤器主要用于对用户请求进行过滤和修改,并将其发送到目标资源或者返回相应的错误响应。典型的应用场景包括:
字符编码:将请求和响应的字符集转换成指定的编码方式,避免乱码问题。
安全控制:检查请求参数是否合法,避免SQL注入等安全问题。
错误处理:捕获异常并返回相应的错误信息,保证系统的稳定性和可靠性。
日志记录:记录请求路径、请求参数、响应结果等信息,方便后续的分析和排查问题。

6、优化策略
(1)、减少拦截器数量:尽量将相关功能集中到一个拦截器中,避免创建过多的拦截器。
(2)、精确配置拦截规则:通过addPathPatterns和excludePathPatterns方法精确配置拦截规则,避免不必要的拦截。
(3)、使用异步处理:在拦截器中使用异步处理,避免阻塞请求处理过程。
(4)、使用缓存:在拦截器中使用缓存,减少对数据库或其他资源的访问。

7、常见问题分析
(1)、拦截器不生效:拦截器不生效的可能原因有很多,其中最常见的包括拦截器未注册到InterceptorRegistry、拦截规则配置错误等。为了解决这个问题,我们需要首先检查拦截器是否已经正确注册到InterceptorRegistry中,然后再检查拦截规则是否配置正确。如果发现问题,需要及时进行调整和修复。
(2)、拦截器执行顺序错误:拦截器执行顺序错误的主要原因是拦截器的注册顺序错误。在实际应用中,拦截器的执行顺序是根据它们在InterceptorRegistry中的注册顺序来决定的。因此,为了解决这个问题,我们需要调整拦截器在InterceptorRegistry中的注册顺序,确保它们按照预期的顺序执行。(靠上注册的会被先执行)
(3)、拦截器影响性能:拦截器影响性能的主要原因是拦截器中的处理逻辑过于复杂或资源消耗过大。为了解决这个问题,我们需要对拦截器的处理逻辑进行优化,尽量减少不必要的计算和资源消耗。同时,我们还可以考虑使用一些性能监控工具,如JProfiler等,来对拦截器的性能进行实时监控和分析,从而找到性能瓶颈并进行优化。

学海无涯苦作舟!!!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值