ⅴiv0x9重装系统0xc000000e更新好吗

Spring3.2异步处理http请求 - 13shu - ITeye技术网站
博客分类:
解决的问题:
目前系统中,有个别的查询比较慢,大概需要几秒才能返回结果。在大量使用此功能时导致系统变慢。
可能会出现的原因:
1、程序问题(包括业务设计、业务逻辑处理、数据库优化等)
2、架构问题
3、其他原因
此处就第二点做一下分析:
用户查询开始到返回结果到页面,此处是一个同步的过程,如果做成异步的能提高系统响应的性能,最近发现servlet3.0有一个新的特性,新增HTTP请求的异步处理,。
由于项目采用的SpringMVC做的,所以查看了下SpringMVC的资料,发现3.2版本对于异步处理有良好的封装。开始做实验
配置servlet3.0
web.xml中配置
&web-app version="3.0"
xmlns="/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/xml/ns/javaee
/xml/ns/javaee/web-app_3_0.xsd"&
&servlet-name&test&/servlet-name&
&servlet-class&org.springframework.web.servlet.DispatcherServlet&/servlet-class&
&load-on-startup&2&/load-on-startup&
&async-supported&true&/async-supported&
&/servlet&
&servlet-mapping&
&servlet-name&test&/servlet-name&
&url-pattern&/&/url-pattern&
&servlet-mapping&
Spring控制层代码修改返回类型为Callable模型
public Callable&String& processUpload(HttpServletRequest request,
final HttpServletResponse response) {
System.out.println("线程名称:"+Thread.currentThread().getName());
return new Callable&String&() {
public String call() throws Exception {
System.out.println("线程名称:"+Thread.currentThread().getName());
response.setContentType("text/charset=utf-8");
response.getWriter().write("nihao");
response.getWriter().close();
} catch (IOException e) {
e.printStackTrace();
控制台输出内容:
13:46:59,875 INFO
[stdout] (http-localhost-127.0.0.1-8080-2) 线程名称:http-localhost-127.0.0.1-8080-2
13:48:57,609 INFO
[stdout] (abc-2) 线程名称:abc-2
Callable内部与外部输出了当前线程的名字,发现线程被切换了,request请求的线程被释放到了web容器中(如:tomcat)。
问题貌似解决了,离下班时间还早于是乎想看下这个神奇的过程是怎么发生的,看了下Spring的源代码,不看不知道,一看吓一跳。
Spring返回的Callable被RequestMappingHandlerAdapter拦截处理了,结果发现Callable被SimpleAsyncTaskExecutor线程池处理了,经过细心的查看代码发现SimpleAsyncTaskExecutor,每当任务被提交到此“线程池(这里就交线程池了)”时,线程池产生一个新的线程去执行Callable中的代码,每次都产生新的线程而且没有上线(默认没有上线,可以设置concurrencyLimit属性来设置线程数的大小),郁闷了.这个肯定不是我需要的。
public void execute(Runnable task, long startTimeout) {
Assert.notNull(task, "Runnable must not be null");
if (isThrottleActive() && startTimeout & TIMEOUT_IMMEDIATE) {
this.concurrencyThrottle.beforeAccess();
doExecute(new ConcurrencyThrottlingRunnable(task));
doExecute(task);
执行任务前会先判断有没有空余的线程空间(concurrencyLimit默认为-1,不执行)
protected void beforeAccess() {
if (this.concurrencyLimit == NO_CONCURRENCY) {
throw new IllegalStateException(
"Currently no invocations allowed - concurrency limit set to NO_CONCURRENCY");
if (this.concurrencyLimit & 0) {
boolean debug = logger.isDebugEnabled();
synchronized (this.monitor) {
boolean interrupted =
while (this.concurrencyCount &= this.concurrencyLimit) {
if (interrupted) {
throw new IllegalStateException("Thread was interrupted while waiting for invocation access, " +
"but concurrency limit still does not allow for entering");
if (debug) {
logger.debug("Concurrency count " + this.concurrencyCount +
" has reached limit " + this.concurrencyLimit + " - blocking");
this.monitor.wait();
catch (InterruptedException ex) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
interrupted =
if (debug) {
logger.debug("Entering throttle at concurrency count " + this.concurrencyCount);
this.concurrencyCount++;
如果没有超过concurrencyLimit,就不会this.monitor.wait();产生新的线程执行任务。
Spring中应该有其他线程池来支持此功能。最终选择ThreadPoolTaskExecutor,看起来与ThreadPoolExecutor类似。
private int corePoolSize = 1;
private int maxPoolSize = Integer.MAX_VALUE;
private int keepAliveSeconds = 60;
private boolean allowCoreThreadTimeOut =
private int queueCapacity = Integer.MAX_VALUE;
private ThreadPoolExecutor threadPoolE
具备线程池的功能,可以设置线程的大小,有缓冲队列,空闲线程存活时间等。
默认corePoolSize=1,maxPoolSize、queueCapacity为整型最大值,keepAliveSeconds=60(单位秒)
&bean id="myThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"&
&property name="corePoolSize" value="5" /&&!--最小线程数 --&
&property name="maxPoolSize" value="10" /&&!--最大线程数 --&
&property name="queueCapacity" value="50" /&&!--缓冲队列大小 --&
&property name="threadNamePrefix" value="abc-" /&&!--线程池中产生的线程名字前缀 --&
&property name="keepAliveSeconds" value="30" /&&!--线程池中空闲线程的存活时间单位秒 --&
&mvc:annotation-driven&
&mvc:async-support task-executor="myThreadPool"
default-timeout="600"&
&mvc:callable-interceptors&
&bean class="com.zhongyu.ABC" /&
&/mvc:callable-interceptors&
&/mvc:async-support&
&/mvc:annotation-driven&
采用annotation-driven方式配置线程池,异步操作拦截器
public &T& Object handleTimeout(NativeWebRequest request, Callable&T& task)
throws Exception {
HttpServletResponse servletResponse = request.getNativeResponse(HttpServletResponse.class);
if (!servletResponse.isCommitted()) {
servletResponse.setContentType("text/charset=utf-8");
servletResponse.getWriter().write("超时了");
servletResponse.getWriter().close();
请求设定default-timeout超时后,会调用拦截器中handleTimeout进行逻辑处理
还需要优化的地方:
由于ThreadPoolTaskExecutor内部缓冲队列采用的是阻塞队列LinkedBlockingDeque,如果队列满了,外部线程会继续等待,需要设置HTTP请求的超时时间
线程池的大小配置
以上问题都需要根据实际业务来做调整。
下载次数: 354
浏览 13889
浏览: 51866 次
来自: 深圳
楼主的qq是多少 有个问题请教
多谢楼主 分享.
&str name=&mm&& ...
这个设置了有效果吗
&str name=&m ...
[b][/b][b][/b][b][/b][b][/b][b] ...基于Spring MVC接收并处置HTTP请求 - VC/MFC当前位置:& &&&基于Spring MVC接收并处置HTTP请求基于Spring MVC接收并处置HTTP请求&&网友分享于:&&浏览:255次基于Spring MVC接收并处理HTTP请求
&&& 要开发一个接收HTTP请求的服务端,由于端口的限制,只能是依托于Tomcat等容器的应用。所以就想到用spring mvc接收http请求,并处理返回。&&& 1.新建maven的web应用,配置web.xml中spring的监听及spring mvc的servlet映射。&?xml version="1.0" encoding="UTF-8"?&
&web-app version="2.4" xmlns="/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/xml/ns/j2ee /xml/ns/j2ee/web-app_2_4.xsd"&
&display-name&Archetype Created Web Application&/display-name&
&context-param&
&param-name&contextConfigLocation&/param-name&
&param-value&
classpath*:spring/*.xml
&/param-value&
&/context-param&
&!-- Filter 定义 --&
&!-- Character Encoding filter --&
&filter-name&encodingFilter&/filter-name&
&filter-class&org.springframework.web.filter.CharacterEncodingFilter&/filter-class&
&init-param&
&param-name&encoding&/param-name&
&param-value&UTF-8&/param-value&
&/init-param&
&init-param&
&param-name&forceEncoding&/param-name&
&param-value&true&/param-value&
&/init-param&
&!-- Filter 映射 --&
&filter-mapping&
&filter-name&encodingFilter&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
&!-- spring容器启动监听器 --&
&listener&
&listener-class&org.springframework.web.context.ContextLoaderListener&/listener-class&
&/listener&
&!-- Spring 刷新Introspector防止内存泄露 --&
&listener&
&listener-class&org.springframework.web.util.IntrospectorCleanupListener&/listener-class&
&/listener&
&!-- session超时定义,单位为分钟 --&
&session-config&
&session-timeout&20&/session-timeout&
&/session-config&
&!-- spring mvc的servlet,加载WEB-INF/SpringSecurity-servlet.xml的配置文件,以启动Spring
MVC模块 --&
&servlet-name&mytest&/servlet-name&
&servlet-class&org.springframework.web.servlet.DispatcherServlet&/servlet-class&
&load-on-startup&2&/load-on-startup&
&/servlet&
&servlet-mapping&
&servlet-name&mytest&/servlet-name&
&url-pattern&*.do&/url-pattern&
&/servlet-mapping&
&welcome-file-list&
&welcome-file&index.html&/welcome-file&
&/welcome-file-list&
&/web-app&&&& 2.配置相应的spring mvc映射文件。在web.xml中配置的mvc servlet名字为mytest,对应的映射文件就是mytest-servlet.xml&?xml version="1.0" encoding="UTF-8"?&
&beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"&
&!-- 对web包中的所有类进行扫描,以完成bean的创建和自动依赖注入功能
&context:component-scan base-package="com.ajita"/&
&!-- 启动Spring mvc的注解功能,完成请求和注解POJO的映射 --&
&bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/&
&!-- 对模型视图的名称的解析 --&
&bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/&
&/beans&&&& 3.新建一个测试用的controller,因为用到了spring mvc的注解功能,要扫描对应的controller包,所以新建的SimpleController要在com.ajita包下面。@Controller
public class SimpleController {
@RequestMapping("/simpletest.do")
public void test(Model model, HttpServletRequest request,
@RequestParam(value = "level", required = false) String level,
@RequestParam(value = "message", required = false) String message,
HttpServletResponse response) {
String ret="heihei";
ServletOutputStream stream = response.getOutputStream();
if(level!=null||message!=null)
ret=level +
stream.print(ret);
stream.close();
} catch (IOException ex) {
}&&& 4.发布,部署到Tomcat下就可以了。我自己测试环境的地址为:http://localhost:8080/HttpServerTest/simpletest.do?level=555&message=ddd ,访问就可以了。&&& 附件是demo代码,还包含了一个调用quartz进行简单任务调度的例子
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有学习Spring必学的Java基础知识(9)----HTTP请求报文 - stamen的程序员之路 - ITeye技术网站
博客分类:
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”。以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助。):
[1] Java反射知识--&Spring IoC :
[2] Java动态代理--&Spring AOP :
[3] 属性编辑器,即PropertyEditor--&Spring IoC:
[4] XML基础知识--&Spring配置:
[5] 注解--&Spring配置:
[6] 线程本地变更,即ThreadLocal--&Spring事务管理:
[7] 事务基础知识--&Spring事务管理:
[8] 国际化信息--&MVC:
[9] HTTP报文--&MVC:
学习Web开发不好好学习HTTP报文,将会“打拳不练功,到老一场空”,你花在犯迷糊上的时间比你沉下心来学习HTTP的时间肯定会多很多。
HTTP请求报文解剖
HTTP请求报文由3部分组成(请求行+请求头+请求体):
下面是一个实际的请求报文:
①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。不过,当前的大多数浏览器只支持GET和POST,Spring 3.0提供了一个HiddenHttpMethodFilter,允许你通过“_method”的表单参数指定这些特殊的HTTP方法(实际上还是通过POST提交表单)。服务端配置了HiddenHttpMethodFilter后,Spring会根据_method参数指定的值模拟出相应的HTTP方法,这样,就可以使用这些HTTP方法对处理方法进行映射了。
②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL,③是协议名称及版本号。
④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
⑤是报文体,它将一个页面表单中的组件值通过param1=value1&param2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1&param2=value2”的方式传递请求参数。
对照上面的请求报文,我们把它进一步分解,你可以看到一幅更详细的结构图:
(1)IE系
是强大的网页数据分析工具,安装后将集成到Internet Explorer工具栏中。它不用代理服务器或一些复杂的网络监控工具,就能抓取请求及响应的完整信息,包括Cookies、消息头、查询参数、响应报文等,是Web应用开发人员的必备工具。
(2)Chrome,firefox
&& 自身的调试器已经很好用了,按F12就可以看到(IE10以上也直接按F12就可以调试了)
HTTP请求报文头属性
报文头属性是什么东西呢?我们不妨以一个小故事来说明吧。
引用快到中午了,张三丰不想去食堂吃饭,于是打电话叫外卖:老板,我要一份[鱼香肉丝],要12:30之前给我送过来哦,我在江湖湖公司研发部,叫张三丰。
这里,你要[鱼香肉丝]相当于HTTP报文体,而“12:30之前送过来”,你叫“张三丰”等信息就相当于HTTP的报文头。它们是一些附属信息,帮忙你和饭店老板顺利完成这次交易。
请求HTTP报文和响应HTTP报文都拥有若干个报文关属性,它们是为协助客户端及服务端交易的一些附属信息。
常见的HTTP请求报文头属性
请求报文可通过一个“Accept”报文头属性告诉服务端 客户端接受什么类型的响应。
如下报文头相当于告诉服务端,俺客户端能够接受的响应类型仅为纯文本数据啊,你丫别发其它什么图片啊,视频啊过来,那样我会歇菜的~~~:
Accept:text/plain
Accept属性的值可以为一个或多个MIME类型的值,关于MIME类型,大家请参考:
这是第一个要说的,客户端的Cookie就是通过这个报文头属性传给服务端的哦!如下所示:
Cookie: $Version=1; Skin=jsessionid=5FCBE13C4C
注意到后台的那个jsessionid=5FCBE13C4C没有,服务端是怎么知道客户端的多个请求是属于一个Session的,原来就是通过HTTP请求报文头的Cookie属性的jsessionid的值关联起来的!(当然也可以通过重写URL的方式将会话ID附带在每个URL的后后面哦)。
表示这个请求是从哪个URL过来的,假如你通过google搜索出一个商家的广告页面,你对这个广告页面感兴趣,鼠标一点发送一个请求报文到商家的网站,这个请求报文的Referer报文头属性值就是。
很多貌似神奇的网页监控软件(如著名的 ),只要在你的网页上放上一段JavaScript,就可以帮你监控流量,全国访问客户的分布情况等报表和图表,其原理就是通过这个Referer及其它一些HTTP报文头工作的。
Cache-Control
对缓存进行控制,如一个请求希望响应返回的内容在客户端要被缓存一年,或不希望被缓存就可以通过这个报文头达到目的。
如以下设置,相当于让服务端将对应请求返回的响应内容不要在客户端缓存(当然响应报文也是通过响应报文头通知浏览器客户端的,这个下面再说):
Cache-Control: no-cache
其它报文头属性
如何访问请求报文头
由于请求报文头是客户端发过来的,服务端当然只能读取了,以下是HttpServletRequest一些用于读取请求报文头的API:
//获取请求报文中的属性名称
java.util.Enumeration&java.lang.String& getHeaderNames();
//获取指定名称的报文头属性的值
java.lang.String getHeader(java.lang.String name)
由于一些请求报文头属性“太著名”了,因此HttpServletRequest为它们提供了VIP的API:
//获取报文头中的Cookie(读取Cookie的报文头属性)
Cookie[] getCookies() ;
//获取客户端本地化信息(读取 Accept-Language 的报文头属性)
java.util.Locale getLocale()
//获取请求报文体的长度(读取Content-Length的报文头属性)
int getContentLength();
HttpServletRequest可以通过
HttpSession getSession()
获取请求所关联的HttpSession,其内部的机理是通过读取请求报文头中Cookie属性的JSESSIONID的值,在服务端的一个会话Map中,根据这个JSESSIONID获取对应的HttpSession的对象。(这样,你就不会觉得HttpSession很神秘了吧,你自己也可以做一个类似的会话管理& )
HTTP响应报文解剖
响应报文结构
HTTP的响应报文也由三部分组成(响应行+响应头+响应体):
以下是一个实际的HTTP响应报文:
①报文协议及版本;
②状态码及状态描述;
③响应报文头,也是由多个属性组成;
④响应报文体,即我们真正要的“干货”。
响应状态码
和请求报文相比,响应报文多了一个“响应状态码”,它以“清晰明确”的语言告诉客户端本次请求的处理结果。
HTTP的响应状态码由5段组成:
1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急...
2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息.
3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
5xx 处理发生,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。
以下是几个常见的状态码:
你最希望看到的,即处理成功!
303 See Other
我把你redirect到其它的页面,目标的URL通过响应报文头的Location告诉你。
引用悟空:师傅给个桃吧,走了一天了
唐僧:我哪有桃啊!去王母娘娘那找吧
304 Not Modified
告诉客户端,你请求的这个资源至你上次取得后,并没有更改,你直接用你本地的缓存吧,我很忙哦,你能不能少来烦我啊!
404 Not Found
你最不希望看到的,即找不到页面。如你在google上找到一个页面,点击这个链接返回404,表示这个页面已经被网站删除了,google那边的记录只是美好的回忆。
500 Internal Server Error
看到这个错误,你就应该查查服务端的日志了,肯定抛出了一堆异常,别睡了,起来改BUG去吧!
有些响应码,Web应用服务器会自动给生成。你可以通过HttpServletResponse的API设置状态码:
//设置状态码,状态码在HttpServletResponse中通过一系列的常量预定义了,如SC_ACCEPTED,SC_OK
void setStatus(int sc)
常见的HTTP响应报文头属性
Cache-Control
响应输出到客户端后,服务端通过该报文头属告诉客户端如何控制响应内容的缓存。
下面,的设置让客户端对响应内容缓存3600秒,也即在3600秒内,如果客户再次访问该资源,直接从客户端的缓存中返回内容给客户,不要再从服务端获取(当然,这个功能是靠客户端实现的,服务端只是通过这个属性提示客户端“应该这么做”,做不做,还是决定于客户端,如果是自己宣称支持HTTP的客户端,则就应该这样实现)。
Cache-Control: max-age=3600
一个代表响应服务端资源(如页面)版本的报文头属性,如果某个服务端资源发生变化了,这个ETag就会相应发生变化。它是Cache-Control的有益补充,可以让客户端“更智能”地处理什么时候要从服务端取资源,什么时候可以直接从缓存中返回响应。
关于ETag的说明,你可以参见:。
Spring 3.0还专门为此提供了一个org.springframework.web.filter.ShallowEtagHeaderFilter(实现原理很简单,对JSP输出的内容MD5,这样内容有变化ETag就相应变化了),用于生成响应的ETag,因为这东东确实可以帮助减少请求和响应的交互。
下面是一个ETag:
ETag: "c284d8af7add"
我们在JSP中让页面Redirect到一个某个A页面中,其实是让客户端再发一个请求到A页面,这个需要Redirect的A页面的URL,其实就是通过响应报文头的Location属性告知客户端的,如下的报文头属性,将使客户端redirect到iteye的首页中:
Set-Cookie
服务端可以设置客户端的Cookie,其原理就是通过这个响应报文头属性实现的:
Set-Cookie: UserID=JohnD Max-Age=3600; Version=1
其它HTTP请求报文头属性
更多其它的HTTP请求头报文,参见:
如何写HTTP请求报文头
在服务端可以通过HttpServletResponse的API写响应报文头的属性:
//添加一个响应报文头属性
void setHeader(String name, String value)
象Cookie,Location这些响应头是有福之人,HttpServletResponse为它们都提供了VIP(非API 哈):
//添加Cookie报文头属性
void addCookie(Cookie cookie)
//不但会设置Location的响应报文头,还会生成303的状态码呢,两者天仙配呢
void sendRedirect(String location)
这些文章摘自于我的《Spring 3.x企业应用开发实战》,我将通过连载的方式,陆续在此发出。欢迎大家讨论。
浏览: 930853 次
来自: 厦门
浏览量:311537
书已买,赞一个
qja 写道我靠。。我的没有show dependency 。 ...
cizezsy 写道请问下有没有勘误表啊?书上的代码有一些错漏 ...
请问下有没有勘误表啊?书上的代码有一些错漏的地方SpringMVC,3种不同的URL路由配置方法(这根本不是一个小问题) - 推酷
SpringMVC,3种不同的URL路由配置方法(这根本不是一个小问题)
SpringMVC中配置URL拦截,非常简单。网上找个示例,就能通过。但是,在我做了好几个Web项目,又参与了别人主导的Web项目时,发现URL配置也非常有学问。
1. 先说说一种比较常见的:
&servlet-name&theDispatcher&/servlet-name&
&servlet-class&org.springframework.web.servlet.DispatcherServlet&/servlet-class&
&init-param&
&param-name&contextConfigLocation&/param-name&
&param-value&classpath:spring/spring-mvc-servlet.xml&/param-value&
&/init-param&
&load-on-startup&1&/load-on-startup&
&/servlet&
&servlet-mapping&
&servlet-name&theDispatcher&/servlet-name&
&url-pattern&*.html&/url-pattern&
&/servlet-mapping&
让SpringMVC指拦截 动态请求,js、css、img等静态资源不经过Spring,直接让Web容器处理。
如果配置了拦截器,也只会拦截.html动态请求。
静态资源不走Spring,也不走拦截器,性能当然是比较好的。
如果使用了Nginx,配置静态资源拦截,让Nginx处理静态资源的访问。因为Nginx在处理静态资源方面,比Tomcat等Web容器要强。
缺点:这种拦截动态请求的方法,比较死板。
2.& 我自己经常有一种需求,
这种不指定.html后缀的其实也是 动态请求,所以我在配置url-pattern喜欢用“/”,即拦截所有的请求。URL是可以灵活配置了,问题又来了,静态资源不再由Tomcat处理,所以必须在SpringMVC中再次配置,
&mvc:resources mapping=&/static/**& location=&/static/& /&
让SpringMVC把static静态资源也处理了。显然,让SpringMVC处理静态资源的性能没有Tomcat直接处理比较高。
理论上,请求中转的次数越多,&性能越差。
本以为万事大吉,虽然静态资源的性能较低,至少程序可以正常运行了,“反正是混过去了”。
进一步的需求,如果在Spring中配置了登录等拦截器,这个时候也会把 静态资源给拦截进来。
&mvc:resources mapping=&/static/**& location=&/static/& /& 这种URL映射,也无法逃脱拦截器的魔爪。
我是怎么发现这个问题的呢?
public class BaseLoginInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LoginUtil.setCurrentUser(null);
initCurrentUser(request, response);
HandlerMethod handlerMethod = (HandlerMethod)
公司的项目,Boss的登录拦截器配置如上,“
HandlerMethod handlerMethod = (HandlerMethod)
”。但是我在自己的项目中,发现这行代码是有问题的。如果静态资源被拦截到,会报错:
java.lang.ClassCastException: org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod
通过异常可以发现,&
Object handler是
ResourceHttpRequestHandler
HandlerMethod。
mvc:resources把静态资源请求交给了
ResourceHttpRequestHandler
处理,因此强制转换是有问题的。
公司项目中Boss的配置之所以没有出现问题,是因为他配置的是只拦截“.html”&动态请求,所以强制转换总是成立的。
---------------------------------------------
我们分析了上述两种情况, 发现“根本矛盾”“根本需求”是啥?
1.动态请求的URL应该非常灵活,/news /news.html都应该算作动态请求。
2.SpringMVC的url-pattern可以配置 / , *.html,或者正则表达式,但是我不太喜欢用正则表达式。
3.如果可能,SpringMVC最好不要拦截静态资源,让Tomcat容器直接处理更好。
&mvc:resources mapping=&/static/**& location=&/static/& /&
这是为了性能考虑。
4.如果线上服务器配置了Nginx,我可以选择让Nginx拦截静态请求,因为比Tomcat处理性能更高。
本地是否配置Nginx,都不需要改动任何代码。
-------------------------------------------------
上面说的 第一种方法的缺陷是,url配置不够灵活。
第二种方法的缺陷是,SpringMVC要拦截静态资源,而且登录拦截器 也会拦截 静态资源,不但性能差,程序还得再次修改,判断HandlerMethod的实际类型。
3.终极解决方案:&
以我习惯用的第2种方法为基础,进一步改进:
&mvc:resources mapping=&/static/**& location=&/static/& /&,不做静态资源请求的映射。
在web.xml里增加如下配置:
&servlet-mapping&
&servlet-name&default&/servlet-name&
&url-pattern&/static/*&/url-pattern&
&/servlet-mapping&
&servlet-mapping&
&servlet-name&default&/servlet-name&
&url-pattern&*.js&/url-pattern&
&/servlet-mapping&
&servlet-mapping&
&servlet-name&default&/servlet-name&
&url-pattern&*.css&/url-pattern&
&/servlet-mapping&
激活Tomcat的defaultServlet来处理静态文件。
网友提问:
这样 SpringMVC不再响应静态资源,登录拦截器也没有问题了。
------------------------------------------------------------------------
详细讨论了上诉3种情况,我的结论是:URL配置根本不是一个简单的问题。
搞IT这门高科技技术的Coder,真心需要研究啊。今天搞点小功能,遇到各种问题,探究了好久,才理清了脉络,单单是解决问题,而不能找到根本原因,在遇到下一个问题的时候,会再次束手无策。
原文首发:
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 0xc0000034 win10系统 的文章

 

随机推荐