一、基本概念
1. 拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
2.拦截器是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制。拦截器不是在web.xml中配置,而是比如struts在struts.xml中配置,或者spring MVC中的mvc配置文件中配置
3. 拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
4. 大部分时候,拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。
5. 自定义拦截器的步骤
1)自定义一个实现了Interceptor(HandlerInterceptorAdapter)接口的类,或者继承抽象类AbstractInterceptor
2)在配置文件中注册定义的拦截器
3)在需要使用Action中引用上述定义的拦截器,为了方便也可以将拦截器定义为默认的拦截器,这样在不加特殊说明的情况下,所有的Action都被这个拦截器拦截。
6. 应用场景
1)日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。
2)权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。
3)性能监控:典型的是慢日志
4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale等其他request请求中的数据
5)OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现
二、常用方法
1. preHandle
1) 预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现)
2) 返回值:true表示继续流程(如调用下一个拦截器或处理器),false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应
2. postHandle
1) 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null
3. afterCompletion
1) 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion
4. 运行流程图
1) 正常流程
2) 中断流程
三、代码示例
1. 写一个自定义拦截器继承HandlerInterceptorAdapter
public class MyInterceptor extends HandlerInterceptorAdapter { // 此处一般继承HandlerInterceptorAdapter适配器即可
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("===========MyInterceptor preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("===========MyInterceptor postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("===========MyInterceptor afterCompletion");
}
}
2. 在spring.xml中或者springMVC的配置文件中
<mvc:interceptors>
<mvc:interceptor>
<!--
/**的意思是所有文件夹及里面的子文件夹
/*是所有文件夹,不含子文件夹
/是web项目的根目录
-->
<mvc:mapping path="/**" />
<!-- 需排除拦截的地址 -->
<!-- <mvc:exclude-mapping path="/userController/login"/> -->
<bean id="commonInterceptor" class="org.shop.interceptor.MyInterceptor"></bean> <!--这个类就是我们自定义的Interceptor -->
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
四、过滤器与拦截器的区别
1. 过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求(包括静态资源也是请求);拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截敏感词汇
1)拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)
2)拦截器不依赖servlet容器,过滤器依赖于servlet容器
3)拦截器只对Action起作用,过滤器可以对所有请求起作用
4)拦截器可以访问Action上下文和值栈中的对象,过滤器不能
5)在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次
6)拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑
7)过滤器包裹住servlet,servlet包裹住拦截器(也就是触发时机不同)
8)拦截器功在对请求权限鉴定方面确实很有用处,第三方的远程调用每个请求都需要参与鉴定,所以这样做非常方便,而且他是很独立的逻辑,这样做让业务逻辑代码很干净
参考网址
Java三大器之拦截器(Interceptor)的实现原理及代码示例
注:文章是经过参考其他的文章然后自己整理出来的,有可能是小部分参考,也有可能是大部分参考,但绝对不是直接转载,觉得侵权了我会删,我只是把这个用于自己的笔记,顺便整理下知识的同时,能帮到一部分人。
ps : 有错误的还望各位大佬指正,小弟不胜感激