博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring-mvc拦截器的原理和范例演示
阅读量:4074 次
发布时间:2019-05-25

本文共 8201 字,大约阅读时间需要 27 分钟。

spring-mvc拦截器

   概述:

    spring-mvc拦截器主要是通过实现 HandlerInterceptor接口,在spring-mvc的核心DispatcherServlet执行主要处理请求方法doDispatch时,由处理器映射器HandlerMapping根据请求对象requset的请求路径,找到对应的Handler以及包装HandlerInterceptor实现类组装成HandlerInterceptorChain,然后由HandlerInterceptorChain根据Handler执行的前后等顺序,调用具体每个拦截器的方法。

   HandlerInterceptor 拦截器主要会在前置处理方法可处理并拦截请求,后置处理方法后执行处理,如果某个拦截器的前置处理执行了,那么最终处理方法不管是前置处理中断请求还是报错,最终处理方法必然执行。

   下面看看DispatcherServlet经过简化的主要执行代码doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {		HttpServletRequest processedRequest = request;		HandlerExecutionChain mappedHandler = null;		try {			ModelAndView mv = null;			Exception dispatchException = null;			try {                // 由HandlerMapping 找到handle并包装拦截器组装成HandlerExecutionChain				mappedHandler = getHandler(processedRequest);				// 因为handler可以是任意类型,因此需要由一个HandlerAdapter来包装调用				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());				                // 前置处理链				if (!mappedHandler.applyPreHandle(processedRequest, response)) {					return;				}                                // 实际调用方法        		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                // 后置处理链				mappedHandler.applyPostHandle(processedRequest, response, mv);			}			catch (Exception ex) {				dispatchException = ex;			}            // 处理视图结果---内部包含拦截器的最终处理(即不异常也要执行最终处理)			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);		}		catch (Exception ex) {            // 最终处理链			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);		}		finally {		    // ....		}

   下面我们自己实现一个spring-mvc的拦截器链以及其他相关类的简易模拟。

一、模拟的主要类介绍

HandlerInterceptor 拦截器

    此接口有三个方法,分别表示在处理器Handler请求执行前,执行后,执行完成的处理。

    
    请求前置处理:preHandle(Request request, Response response, Handler handler)
    请求后置处理:postHandle(Request request,Response response, Handler handler)
    请求最终处理:afterCompletion(Request request, Response response, Handler handler, Exception exc)
        
HandlerExecutionChain  拦截器链:
 
    功能概述:
    拦截器链实例内部有List<HandlerInterceptor> 的变量,初始化的时候用来添加拦截器, 并且用了一个int  类型interceptorIndex变量,它表示多少个拦截器执行了前置操作preHandle()方法,如果前置方法出错,那么已经完成前置操作的拦截器,需要做对应的afterCompletion最终处理的操作, afterCompletion操作是执行完成或执行出错会进行执行的方法。
    
其他类:
    Handler 处理器,本来是用处理器适配器进行执行请求,简化就设置成一个固定处理请求的Handler类
    Request 请求类, 简化成一个msg的pojo类
    Response 响应类,简化成一个msg的pojo类

二、范例代码

public class MvcFilterDemo {		/**模拟request*/	static class Request {		public Request(String msg) {			super();			this.msg = msg;		}		private String msg;		public String getMsg() {			return msg;		}		public void setMsg(String msg) {			this.msg = msg;		}	}		/**模拟response*/	static class Response{		private String msg;		public String getMsg() {			return msg;		}		public void setMsg(String msg) {			this.msg = msg;		}	}		/**处理接口*/	static interface Handler {		public Object invoke (Request request, Response response) ;	}		/** 拦截器接口*/	static interface HandlerInterceptor {		boolean preHandle(Request request, Response response, Handler handler);		void postHandle(Request request, Response response, Handler handler);		void afterCompletion(Request request, Response response, Exception exc);	}		/**	 * 拦截器链	 */	static class HandlerExecutionChain {		private Handler handler;		private HandlerInterceptor[] interceptors; // 拦截链调用辅助用途		private List
interceptorList = new ArrayList
(); // 装拦截器 private int interceptorIndex = -1; // 前置执行的角标 public HandlerExecutionChain(Handler handler) { this.handler = handler; } public Handler getHandler() { return this.handler; } public void addInterceptor(HandlerInterceptor interceptor) { this.interceptorList.add(interceptor); } public HandlerInterceptor[] getInterceptors() { if (this.interceptors == null && this.interceptorList != null) { this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]); } return this.interceptors == null ? new HandlerInterceptor[0] : this.interceptors; } // 1、前置执行所有 : 每次for循环,后记录已经执行的拦截器角标,并且如果拦截器返回false,此时的最后一个拦截器要执行下最终处理方法。 boolean applyPreHandle(Request request, Response response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } return true; } // 2、后置执行所有:按反方向全部拦截器都执行。 void applyPostHandle(Request request, Response response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler); } } // 3、最终执行:前置操作过不管是否中断请求还是出错,这个都会进行执行。 void triggerAfterCompletion(Request request, Response response, Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, ex); } catch (Throwable ex2) { } } } } /** * 请求调度总类 */ static class DispatcherServlet{ private HandlerExecutionChain chain ; public void setChain(HandlerExecutionChain chain) { this.chain = chain; } public void doService(Request request, Response response) throws Exception { Handler handler = chain.getHandler(); try { // 前置拦截 --- 如果false,内部会 if (!chain.applyPreHandle(request, response)) { return; } Exception dispatchException = null; try { handler.invoke(request, response); // 后置执行 chain.applyPostHandle(request, response); } catch (Exception e) { dispatchException = e; } // 最终执行 chain.triggerAfterCompletion(request, response, dispatchException); } catch (Exception e) { chain.triggerAfterCompletion(request, response, e); } finally { // .... } } } 测试阶段// public static class MyHandler implements Handler { @Override public Object invoke(Request request, Response response) { System.out.println("handler处理方法进行实际处理"); String old = request.getMsg() ; request.setMsg(old + "[real excute]"); return "hello wolrd"; } } static class HandlerInterceptorOne implements HandlerInterceptor { @Override public boolean preHandle(Request request, Response response, Handler handler) { String old = request.getMsg() ; request.setMsg(old + "[one excute]"); System.out.println("one 前置执行"); return true; } @Override public void postHandle(Request request, Response response, Handler handler) { System.out.println("one 后置执行"); } @Override public void afterCompletion(Request request, Response response, Exception exc) { System.out.println("one 最终执行"); } } static class HandlerInterceptorTwo implements HandlerInterceptor { @Override public boolean preHandle(Request request, Response response, Handler handler) { String old = request.getMsg() ; request.setMsg(old + "[two excute]"); System.out.println("two 前置执行"); return true; } @Override public void postHandle(Request request, Response response, Handler handler) { System.out.println("two 后置执行"); } @Override public void afterCompletion(Request request, Response response, Exception exc) { System.out.println("two 最终执行"); } } /** * 测试: */ public static void main(String[] args) throws Exception { DispatcherServlet dispatcherServlet = new DispatcherServlet(); MyHandler myHandler = new MyHandler(); HandlerInterceptorOne oneInterceptor = new HandlerInterceptorOne(); HandlerInterceptorTwo twoInterceptor = new HandlerInterceptorTwo(); HandlerExecutionChain chain = new HandlerExecutionChain(myHandler); chain.addInterceptor(oneInterceptor); chain.addInterceptor(twoInterceptor); dispatcherServlet.setChain(chain); Request request = new Request("base request"); Response response = new Response(); dispatcherServlet.doService(request, response); System.out.println("最终结果" + request.getMsg());// one 前置执行// two 前置执行// handler处理方法进行实际处理// two 后置执行// one 后置执行// two 最终执行// one 最终执行// 最终结果base request[one excute][two excute][real excute] } }

完毕!

 

 

 

转载地址:http://reuni.baihongyu.com/

你可能感兴趣的文章
Qt 静态编译后的exe太大, 可以这样压缩.
查看>>
WCF添加服务失败一则
查看>>
ASP.NET MVC
查看>>
在公司内网上创建自己的 OSM.Planet 街道级别地图服务器及其客户端程序
查看>>
微软云Azure Website 远程调试
查看>>
经典DOS游戏皇帝攻略(曾经的回忆)
查看>>
风后握奇经
查看>>
compass电子罗盘
查看>>
swfdump——从内存中提取swf的工具
查看>>
VS 的编译选项 build下的 platform target -- Any CPU和x86有什么影响?
查看>>
Windows 运行时组件
查看>>
MIT License
查看>>
UWP蓝牙的例子
查看>>
Java的注解机制——Spring自动装配的实现原理
查看>>
JAVA代码中加了Try...Catch的执行顺序
查看>>
银狐云服务架构V0.1
查看>>
开启云时代,银狐H5游戏云通迅框架解决方案出炉!
查看>>
netty5和4.x,3.x的一些区别
查看>>
JAVA中遇到 UTF-八 序列的字节 1 无效
查看>>
Unity3D中Update()与FixedUpdate()的区别
查看>>