spring mvc DispatcherServlet之前端控制器架构详解
前端控制器是整个mvc框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。前端控制器既可以使用filter实现(struts2采用这种方式),也可以使用servlet来实现(spring mvc框架)。
dispatcherservlet 作为前置控制器是web服务器的入口,是spring mvc最重要的一个类,通过它的生命周期可以加深对web服务器的理解。
servlet的生命周期
首先我们回忆一下servlet的生命周期:
servlet生命周期分为三个阶段:【servlet生命周期与工作原理详解】
1.初始化阶段 调用init()方法。servlet被装载后,servlet容器创建一个servlet实例并且调用servlet的init()方法进行初始化。在servlet的整个生命周期内,init()方法只被调用一次。
2.响应客户请求阶段 调用service()方法
3.终止阶段 调用destroy()方法
servlet初始化阶段
在下列时刻servlet容器装载servlet:
1.servlet容器启动时自动装载某些servlet,实现它只需要在web.xml文件中的<servlet></servlet>之间添加如下代码:
<loadon-startup>1</loadon-startup>
2.在servlet容器启动后,客户首次向servlet发送请求
3.servlet类文件被更新后,重新装载servlet
dispatcherservlet的结构
复习了上述知识后我们来看看dispatcherservlet的结构:
dispatcherservlet继承自抽象类:frameworkservlet,间接继承了httpservlet (frameworkservlet继承自httpservletbean,而httpservletbean继承自httpservlet )
servlet的初始化
protected void initstrategies(applicationcontext context) { initmultipartresolver(context); //文件上传解析,如果请求类型是multipart将通过multipartresolver进行文件上传解析; initlocaleresolver(context); //本地化解析 initthemeresolver(context); //主题解析 inithandlermappings(context); //通过handlermapping,将请求映射到处理器 inithandleradapters(context); //通过handleradapter支持多种类型的处理器 inithandlerexceptionresolvers(context); //如果执行过程中遇到异常将交给handlerexceptionresolver来解析 initrequesttoviewnametranslator(context); //直接解析请求到视图名 initviewresolvers(context); //通过viewresolver解析逻辑视图名到具体视图实现 initflashmapmanager(context); //flash映射管理器 }
servlet如何处理请求:
servlet的service方法处理http请求。
frameworkservlet.java 定义了servlet的service和destroy方法,如下所示:
/** * override the parent class implementation in order to intercept patch * requests. */ @override protected void service(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string method = request.getmethod(); if (method.equalsignorecase(requestmethod.patch.name())) { processrequest(request, response); } else { super.service(request, response); } }
我们知道http请求类型有七种(外加一个option选项),定义如下:
public enum requestmethod { get, head, post, put, patch, delete, options, trace }
frameworkservlet的service()处理不同的请求,我们以常见的post来说明:
/** * process this request, publishing an event regardless of the outcome. * <p>the actual event handling is performed by the abstract * {@link #doservice} template method. */ protected final void processrequest(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { long starttime = system.currenttimemillis(); throwable failurecause = null; localecontext previouslocalecontext = localecontextholder.getlocalecontext(); localecontext localecontext = buildlocalecontext(request); requestattributes previousattributes = requestcontextholder.getrequestattributes(); servletrequestattributes requestattributes = buildrequestattributes(request, response, previousattributes); webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request); asyncmanager.registercallableinterceptor(frameworkservlet.class.getname(), new requestbindinginterceptor()); initcontextholders(request, localecontext, requestattributes); try { doservice(request, response); } catch (servletexception ex) { failurecause = ex; throw ex; } catch (ioexception ex) { failurecause = ex; throw ex; } catch (throwable ex) { failurecause = ex; throw new nestedservletexception("request processing failed", ex); } finally { resetcontextholders(request, previouslocalecontext, previousattributes); if (requestattributes != null) { requestattributes.requestcompleted(); } if (logger.isdebugenabled()) { if (failurecause != null) { this.logger.debug("could not complete request", failurecause); } else { if (asyncmanager.isconcurrenthandlingstarted()) { logger.debug("leaving response open for concurrent processing"); } else { this.logger.debug("successfully completed request"); } } } publishrequesthandledevent(request, starttime, failurecause); } }
frameworkservlet 抽象定义了处理流程,留待子类来实现该方法,完成具体的请求处理。
/** * subclasses must implement this method to do the work of request handling, * receiving a centralized callback for get, post, put and delete. * <p>the contract is essentially the same as that for the commonly overridden * {@code doget} or {@code dopost} methods of httpservlet. * <p>this class intercepts calls to ensure that exception handling and * event publication takes place. * @param request current http request * @param response current http response * @throws exception in case of any kind of processing failure * @see javax.servlet.http.httpservlet#doget * @see javax.servlet.http.httpservlet#dopost */ protected abstract void doservice(httpservletrequest request, httpservletresponse response) throws exception;
具体实现如下:
/** * exposes the dispatcherservlet-specific request attributes and delegates to {@link #dodispatch} * for the actual dispatching. */ @override protected void doservice(httpservletrequest request, httpservletresponse response) throws exception { if (logger.isdebugenabled()) { string resumed = webasyncutils.getasyncmanager(request).hasconcurrentresult() ? " resumed" : ""; logger.debug("dispatcherservlet with name '" + getservletname() + "'" + resumed + " processing " + request.getmethod() + " request for [" + getrequesturi(request) + "]"); } // keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. map<string, object> attributessnapshot = null; if (webutils.isincluderequest(request)) { attributessnapshot = new hashmap<string, object>(); enumeration<?> attrnames = request.getattributenames(); while (attrnames.hasmoreelements()) { string attrname = (string) attrnames.nextelement(); if (this.cleanupafterinclude || attrname.startswith("org.springframework.web.servlet")) { attributessnapshot.put(attrname, request.getattribute(attrname)); } } } // make framework objects available to handlers and view objects. request.setattribute(web_application_context_attribute, getwebapplicationcontext()); request.setattribute(locale_resolver_attribute, this.localeresolver); request.setattribute(theme_resolver_attribute, this.themeresolver); request.setattribute(theme_source_attribute, getthemesource()); flashmap inputflashmap = this.flashmapmanager.retrieveandupdate(request, response); if (inputflashmap != null) { request.setattribute(input_flash_map_attribute, collections.unmodifiablemap(inputflashmap)); } request.setattribute(output_flash_map_attribute, new flashmap()); request.setattribute(flash_map_manager_attribute, this.flashmapmanager); try { dodispatch(request, response); } finally { if (webasyncutils.getasyncmanager(request).isconcurrenthandlingstarted()) { return; } // restore the original attribute snapshot, in case of an include. if (attributessnapshot != null) { restoreattributesafterinclude(request, attributessnapshot); } } }
重头戏,作为请求分发器的实现:
功能:1. 把请求分发到handler(按照配置顺序获取servlet的映射关系获取handler);2. 根据servlet已安装的 handleradapters 去查询第一个能处理的handler;3. handler激发处理请求
/** * process the actual dispatching to the handler. * <p>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. * <p>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 */ protected void dodispatch(httpservletrequest request, httpservletresponse response) throws exception { httpservletrequest processedrequest = request; handlerexecutionchain mappedhandler = null; boolean multipartrequestparsed = false; webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request); try { modelandview mv = null; exception dispatchexception = null; try { processedrequest = checkmultipart(request); multipartrequestparsed = (processedrequest != request); // determine handler for the current request. mappedhandler = gethandler(processedrequest); if (mappedhandler == null || mappedhandler.gethandler() == null) { nohandlerfound(processedrequest, response); return; } // determine handler adapter for the current request. handleradapter ha = gethandleradapter(mappedhandler.gethandler()); // process last-modified header, if supported by the handler. string method = request.getmethod(); boolean isget = "get".equals(method); if (isget || "head".equals(method)) { long lastmodified = ha.getlastmodified(request, mappedhandler.gethandler()); if (logger.isdebugenabled()) { logger.debug("last-modified value for [" + getrequesturi(request) + "] is: " + lastmodified); } if (new servletwebrequest(request, response).checknotmodified(lastmodified) && isget) { return; } } if (!mappedhandler.applyprehandle(processedrequest, response)) { return; } try { // actually invoke the handler. mv = ha.handle(processedrequest, response, mappedhandler.gethandler()); } finally { if (asyncmanager.isconcurrenthandlingstarted()) { return; } } applydefaultviewname(request, mv); mappedhandler.applyposthandle(processedrequest, response, mv); } catch (exception ex) { dispatchexception = ex; } processdispatchresult(processedrequest, response, mappedhandler, mv, dispatchexception); } catch (exception ex) { triggeraftercompletion(processedrequest, response, mappedhandler, ex); } catch (error err) { triggeraftercompletionwitherror(processedrequest, response, mappedhandler, err); } finally { if (asyncmanager.isconcurrenthandlingstarted()) { // instead of posthandle and aftercompletion mappedhandler.applyafterconcurrenthandlingstarted(processedrequest, response); return; } // clean up any resources used by a multipart request. if (multipartrequestparsed) { cleanupmultipart(processedrequest); } } }
servlet销毁
/** * close the webapplicationcontext of this servlet. * @see org.springframework.context.configurableapplicationcontext#close() */ @override public void destroy() { getservletcontext().log("destroying spring frameworkservlet '" + getservletname() + "'"); // only call close() on webapplicationcontext if locally managed... if (this.webapplicationcontext instanceof configurableapplicationcontext && !this.webapplicationcontextinjected) { ((configurableapplicationcontext) this.webapplicationcontext).close(); } }
小结:
本文因篇章限制,仅仅介绍了请求处理的流程,没有对代码进行深入的分析,接下来的文章将从细微处着手,分析spring的代码之美。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Android 显示GIF图片实例详解