Spring MVC拦截器配置及其原理分析_springmvc freemarker 拦截器-程序员宅基地

技术标签: web网站开发  SpringMVC原理分析  java  SpringMVC  SpringMVC拦截器  SpringMVC配置  

原文:Spring MVC拦截器配置及其原理分析

源代码下载地址:http://www.zuidaima.com/share/1751865167973376.htm


SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。

一、Servlet Filter与Spring interceptor的执行顺序

Filter有顺序吗?我们怎么控制filter的执行顺序。通过Tomcat的代码分析,servlet在Filter执行完成后才调用,如有多个filter怎么控制执行顺序,首先会想到在web.xml配置某个参数,例如order之类的,但查找一下一番,servlet并没有这个参数。试试filter Mapping的配置的先后顺序,果然有效,原来filter的执行顺序就考filter mapping在web.xml中的顺序。

spring interceptor也是这样的执行顺序,不过interceptor多一个配置参数order通过他也可以来实现interceptor的执行顺序。很多应用场景中,执行顺序还是重要的,比如cache和transaction interceptor的执行顺序,很显然cache应该在transaction之前,这样发现命中了就不用打开事务,如果transaction在前,每次都打开事务即使cache命中,这是一个无谓东动作。

二、利用springMVC的interceptor实现页面性能监控(Filter亦可)

调优第一步,找出耗时比较长的页面进行优化。利用interceptor能轻易搞定。interceptor提供了preHandle和postHandle以及afterCompletion三个方法。preHandle调用controller具体方法之前调用,postHandle完成具体方法之后调用,afterCompletion完成对页面的render以后调用,至此整个页面渲染完成。也就是说我们在preHandle记录开始的时间,在afterCompletion记录结束的时间,就可或者整个页面生成的时间。Spring自带StopWatch工具类来实现时间跟踪,关键一点interceptor不是线程安全的。我们需要借助threadlocal来实现线程安全。

@Override 
public boolean preHandle(HttpServletRequest request, 
		HttpServletResponse response, Object handler) throws Exception { 
	if(usePerformance){ 
		StopWatch stopWatch = new StopWatch(handler.toString()); 
		stopWatchLocal.set(stopWatch); 
		stopWatch.start(handler.toString()); 
	} 
	 
	return true; 
} 

@Override 
public void afterCompletion(HttpServletRequest request, 
		HttpServletResponse response, Object handler, Exception ex) 
		throws Exception { 
	if(usePerformance){ 
		StopWatch stopWatch = stopWatchLocal.get(); 
		stopWatch.stop(); 
		String currentPath = request.getRequestURI(); 
		String queryString  = request.getQueryString(); 
		queryString = queryString == null ? "":"?" + queryString; 
		log.info("access url path:" + currentPath + queryString +  " |time:" + stopWatch.getTotalTimeMillis()); 
		stopWatchLocal.set(null); 
	} 
} 
 

三、SpringMVC 拦截器实现分析

SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。哪不难想到我们在执行controller之前做某些动作,执行完毕做某些动作,render完成做某些动作。SpringMVC的拦截器对应提供了三个preHandle,postHandle,afterCompletion方法。只需在三个方法内写我们需要的逻辑就行,多了都是废话,还是代码实在。 

 

如果你没有使用springMVC可以使用filter来完成:

stopWatch.start(); 
doFilterChain(); 
stopWatch.stop(); 

三、SpringMVC 拦截器实现分析

SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。哪不难想到我们在执行controller之前做某些动作,执行完毕做某些动作,render完成做某些动作。SpringMVC的拦截器对应提供了三个preHandle,postHandle,afterCompletion方法。只需在三个方法内写我们需要的逻辑就行,多了都是废话,还是代码实在。

HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); 
if (interceptors != null) { 
	for (int i = 0; i < interceptors.length; i++) { 
		HandlerInterceptor interceptor = interceptors[i]; 
//ha.handle是调用具体的controller在此之前执行preHandle                      if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { 
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); 
			return; 
		} 
		interceptorIndex = i; 
	} 
} 

// Actually invoke the handler. 
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 

完成调用之后,调用render(),最后执行afterCompletion()。

if (interceptors != null) { 
		for (int i = interceptors.length - 1; i >= 0; i--) { 
			HandlerInterceptor interceptor = interceptors[i]; 
			interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); 
		} 
	} 
} 
catch (ModelAndViewDefiningException ex) { 
	logger.debug("ModelAndViewDefiningException encountered", ex); 
	mv = ex.getModelAndView(); 
} 
catch (Exception ex) { 
	Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); 
	mv = processHandlerException(processedRequest, response, handler, ex); 
	errorView = (mv != null); 
} 

// Did the handler return a view to render? 
if (mv != null && !mv.wasCleared()) { 
	render(mv, processedRequest, response); 
	if (errorView) { 
		WebUtils.clearErrorRequestAttributes(request); 
	} 
} 
else { 
	if (logger.isDebugEnabled()) { 
		logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + 
				"': assuming HandlerAdapter completed request handling"); 
	} 
} 

// Trigger after-completion for successful outcome. 
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);  
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/springmvc_freemarker/article/details/50747391

智能推荐

毕设分享 python大数据房价预测与可视化系统-程序员宅基地

文章浏览阅读1.2k次,点赞19次,收藏15次。# 0 简介今天学长向大家介绍一个适合作为毕设的项目毕设分享 python大数据房价预测与可视化系统项目获取:https://gitee.com/assistant-a/project-sharing对于数据挖掘工程师来说,有时候需要抓取地理位置信息,比如统计房子周边基础设施信息,比如医院、公交车站、写字楼、地铁站、商场等,一般的爬虫可以采用python脚本爬取,有很多成型的框架如scrapy,但是想要爬百度地图就必须遵循它的JavaScriptApi,那么肯定需要自己写JavaScript脚本与百度API

在vscode工具中,使用eslint,stylelint,htmlhint对vue项目代码格式的检查_vscode stylelint 总是检查js 语法-程序员宅基地

文章浏览阅读4.6k次。1. 对js代码格式的检查:首先全局安装以下插件:“eslint”“vue-eslint-parser”“babel-eslint”“eslint-config-alloy”“eslint-plugin-html”“eslint-plugin-import”“eslint-plugin-node”“eslint-plugin-promise”在项目根目录添加 .eslint..._vscode stylelint 总是检查js 语法

C语言经典算法-6-程序员宅基地

文章浏览阅读945次,点赞22次,收藏23次。c语言经典算法,数字拆解,选择、插入、气泡排序,shell排序,shaker排序

yum的repo文件详解、以及epel简介、yum源的更换_epel.repo-程序员宅基地

文章浏览阅读5.6k次,点赞2次,收藏18次。一、什么是repo文件repo文件是Fedora中yum源(软件仓库)的配置文件,通常一个repo文件定义了一个或者多个软件仓库的细节内容,例如我们将从哪里下载需要安装或者升级的软件包,repo文件中的设置内容将被yum读取和应用!YUM的工作原理并不复杂,每一个 RPM软件的头(header)里面都会纪录该软件的依赖关系,那么如果可以将该头的内容纪录下来并且进行分析,可以知道每个软件在安装之前需要额外安装 哪些基础软件。也就是说,在服务器上面先以分析工具将所有的RPM档案进行分析,然后将该分析纪录下来_epel.repo

mac mysql的使用教程_Navicat for mac使用教程-程序员宅基地

文章浏览阅读710次。1.安装后第一次打开会弹出此框要求你连接mysql。连接名随便填,password 默认为 root.屏幕快照 2014-12-16 上午12.03.48.png2.完成之后,进入主界面你会看到你刚看创建的Connection.(这里我创建的连接名字为DB)屏幕快照 2014-12-16 上午12.06.58.png3.打开DB,你会发现里面有几个已经创建的数据库,这是系统自动帮你创建的,不用管他..._navicat for mysql用法 mac版

uniapp小程序实现内容自适应并向上滚动弹幕_uniapp 弹幕 滚动-程序员宅基地

文章浏览阅读691次,点赞9次,收藏7次。uniapp小程序实现内容自适应并向上滚动弹幕_uniapp 弹幕 滚动

随便推点

Arduino for PKE8720DF-C13-F10——UART产生时钟信号_串口实现时钟信号-程序员宅基地

文章浏览阅读155次。PKE8720DF-C13-F10提供三组UART,SERIAL1_TX(PB19) 和 SERIAL1_RX(PB18)、SERIAL2_TX(PA12) 和 SERIAL2_RX(PA13)、LOG_TX(PA7) 和 LOG_RX(PA8)PKE8720DF-C13-F10提供了三组UART,使用其中的SERIAL1这组UART来产生时钟信号,定义UART_TX及UART_RX对应的Pin脚。PKE8720DF-C13-F10开发板UART端口配置。1 x PKE8720DF-C13-F10开发板。_串口实现时钟信号

用Python做50道ACM之《Number Triangle 》_python数字三角形acm-程序员宅基地

文章浏览阅读703次。5.Number Trianglehttp://acm.fzu.edu.cn/problem.php?pid=1004自底向上地解决,从倒数第二行开始,每个数字用其本身和其左右子节点中较大值的和来替代。# 动态规划import sysline_left=0 # 每个用例剩余未读取行数while true: read_in=sys.stdin.readline() if..._python数字三角形acm

android 获取api key_安卓应用内置api转id-程序员宅基地

文章浏览阅读785次。1. 首先先要获取你的debug keystore位置:打开Eclipse--->Windows--->Preferences--->Android--->Build查看默认的debug keystore位置,我的是C:/Documents and Settings/MYNAME /.android/debug.keystore2. 在cmd中执行:keytool -l_安卓应用内置api转id

基于LOAM框架的激光SLAM开源程序汇总-程序员宅基地

文章浏览阅读655次。点击上方“计算机视觉工坊”,选择“星标”干货第一时间送达1 前言LOAM, 即Lidar Odometry and Mapping,是 Ji Zhang 博士于2014年提出的使用激光雷达..._loam系开源算法汇总

sentaurus光电器件仿真笔记(sde部分)(一)_sentaurus网格如何划分-程序员宅基地

文章浏览阅读5.8k次,点赞4次,收藏42次。项目场景:最近由于项目组做光电器件有流片机会,所以在找了个简单的器件进行仿真实现。mesh网格策略:一般的三维器件仿真模拟的网格策略为:(sdedr:define-refinement-window “W.Global” “Cuboid”(position -200 -200 0)(position 200 200 0) ..._sentaurus网格如何划分

微信公众号支付 错误chooseWXPay:fail, the permission value is offline verifying-程序员宅基地

文章浏览阅读4.8w次,点赞3次,收藏3次。一是在模拟器中实行发起支付,要在真机是发起二是微信公众号支付授权目录要填写实际发起支付的url地址,比如你的页面是http://www.newfms.com/order/pay/id-115,那么此处应该填http://www.newfms.com/order/pay/ 如果在uni-APP 生成的h5网址结构中比如:https://www.xxxx.cn/h5/#/pages/s..._choosewxpay:fail, the permission value is offline verifying

推荐文章

热门文章

相关标签