Spring MVC 之servlet代理代码研究
这里主要探讨spring web mvc在serlvet2.4中如何通过web.xml中的配置 ,将缺省的javax.sevelt.httpservlet 对request和response进行扩展的。首先,在web.xml中,通过:<servlet> <servlet-name>springapp</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet><servlet-mapping> <servlet-name>springapp</servlet-name> <url-pattern>*.htm</url-pattern></servlet-mapping>将web对指定的url请求提交org.springframework.web.servlet.DispatcherServlet类 进行处理。 事实上,处理交给DispatcherServlet时,需要通过以下几个类才能达到本体:
Servelt 控制器走向
实际上,serlvlet的request与response到DispatcherServlet才得到封装处理,其他类都只是进行控制传递,不过对init方法,org.springframework.web.servlet.HttpServletBean已经重载并在config配置中加入了bean的属性。在org.springframework.web.servlet.FrameworkServlet又对init方法进行了扩展,加入了计时器,对初始化时间(initFrameworkServlet())进行统计,最后的初始化工作交给了DispatcherServlet的initFrameworkServlet()方法,该方法最终可以使得用户可以通过配置文件对bean进行配置.注意的是如何得到配置文件及如何从配置文件获取信息是通过FrameworkServlet的getWebApplicationContext()方法.
在DispatcherServlet,从doServices() ->doDispatch()方法中,request对象被设置了4 个属性:其中跟配置文件相关的属性是:/* Request attribute to hold the current web application context.*/属性名:WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName()+".CONTEXT";值: getWebApplicationContext()
在doDispatch()中,request对象首先通过:LocaleContextHolder.setLocaleContext(new LocaleContext() { public Locale getLocale() { return localeResolver.resolveLocale(request); } });
方法处理,使得request中的私有静态字段与该对应的request请求者(一个thread线程)绑定.这样其他的request请求者就无法访问到别的requet中的私有字段了. 附注: LocaleContextHolder.class:相关的方法 ThreadLocal localeContextHolder = new InheritableThreadLocal() setLocaleContext(LocaleContext localeContext) { localeContextHolder.set(localeContext); }
InheritableThreadLocal.class的set方法: /** * Sets the current thread's copy of this thread-local variable * to the specified value. */ public void set(Object value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
其后:// Expose current RequestAttributes to current thread. RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); RequestContextHolder.setRequestAttributes(requestAttributes);下面的操作都是为获取下个handler (其实就是servlet控制器),:
将当前的request属性绑定到当前的request请求者上.注意的是, getRequestAttributes与setRequestAttributes都是针对当前线程的.
下面的操作都是为获取下个handler (其实就是servlet控制器),
首先通过getHandler()查找如果找到,则继续判断是否存在多个映射关系mapping(多个控制器),如果是,则根据先后(通过List handlerMappings ,该list在初始化方法中被初始化. )返回单个hander.,并在request对象中设置了一个标记:request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);
对request对象的处理已经差不多了,该将控制权提交给被请求的那个hander了,在最后的的finally块中, doDispatch()做了3件事情:清除request操作中的临时变量所占的资源重置request请求者(curren thread)所绑定的资源,避免多余绑定重置request请求者(curren thread)线程。
由于doDispatch()方法并没有显示的将dispather控制权交给下个hander(也就是request应该被那个hander处理),因此该把当前的request请求交给那个bean(在doDispatch会指定,实际上我们是在applicationcontext.xml中指定的)就由HandlerAdapters来做的,可以看doDispatch()方法的注释:/** * Process the actual dispatching to the handler.* The handler will be obtained by applying the servlet's* HandlerMappings in order.* The HandlerAdapter will be obtained by querying the servlet's installed* HandlerAdapters to find the first that supports the handler class.* All HTTP methods are handled by this method. It's up to HandlerAdapters* or handlers themselves to decide which methods are acceptable.* @param request current HTTP request* @param response current HTTP response* @throws Exception in case of any kind of processing failure*/