< mvc:default-servlet-handler />的作用
在Spring MVC框架中,针对静态资源的请求处理的常见策略有两种:1. 配置< mvc:default-servlet-handler />标签,通过容器来处理;2. 配置< mvc:resources />标签,通过框架来处理。
从Spring MVC的XML Schema文件说明中可以知道,通过< mvc:default-servlet-handler />标签的配置可以使DispatcherServlet在声明过滤路径为"/"时,依旧使用容器中默认的Servlet来处理静态资源请求。在整个处理过程中,会声明注册DefaultServletHttpRequestHandler类来进行从MVC框架到容器Servlet的转发处理。
通过该处理策略弥补了Spring MVC框架对处理静态资源时的不足,可以有效提升静态资源的请求处理效率。同时又兼顾了框架对请求统一管理的需求,并能够时请求的URL命名更符合REST风格,降低人工配置请求后缀名来进行请求分类的管理成本。
DefaultServletHttpRequestHandler类的作用
在DefaultServletHttpRequestHandler类中声明了诸如Tomcat, Jetty, JBoss, GlassFish以及WebLogic, WebSphere等容器中默认Servlet的命名。在系统启动时,通过匹配容器中的RequestDispatcher类来进行注册。
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
if (!StringUtils.hasText(this.defaultServletName)) {
if (this.servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {
this.defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
}
else if (this.servletContext.getNamedDispatcher(GAE_DEFAULT_SERVLET_NAME) != null) {
this.defaultServletName = GAE_DEFAULT_SERVLET_NAME;
}
else if (this.servletContext.getNamedDispatcher(RESIN_DEFAULT_SERVLET_NAME) != null) {
this.defaultServletName = RESIN_DEFAULT_SERVLET_NAME;
}
else if (this.servletContext.getNamedDispatcher(WEBLOGIC_DEFAULT_SERVLET_NAME) != null) {
this.defaultServletName = WEBLOGIC_DEFAULT_SERVLET_NAME;
}
else if (this.servletContext.getNamedDispatcher(WEBSPHERE_DEFAULT_SERVLET_NAME) != null) {
this.defaultServletName = WEBSPHERE_DEFAULT_SERVLET_NAME;
}
else {
throw new IllegalStateException("Unable to locate the default servlet for serving static content. " +
"Please set the 'defaultServletName' property explicitly.");
}
}
}
当请求抵达该Handler类时会直接调用对应的RequestDispatcher来forward转发请求至容器处理请求。
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
if (rd == null) {
throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
this.defaultServletName + "'");
}
rd.forward(request, response);
}
由此完成从MVC框架到容器的请求转发与处理。
< mvc:default-servlet-handler />的配置
除了可以通过使用DefaultServletHttpRequestHandler类中默认提供的容器,同样可以通过default-servlet-name属性来配置运行容器中默认Servlet的命名,以达到灵活配置并满足在任意Java Web容器中运行的需求。
< mvc:default-servlet-handler />的注意事项
由于在该配置下,预期是DispatcherServlet拦截的全部请求若无对应的Handler进行处理时,会转发到容器中的默认的Servlet进行处理。因此,将其他自定义的Handler中配置的URL HandlerMappings的order值小于DefaultServletHttpRequestHandler类的order值Integer.MAX_VALUE是非常重要的,以避免URL在匹配时无法满足预期。