欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring mvc DispatcherServlet之前端控制器架构详解

程序员文章站 2023-11-20 19:53:52
前端控制器是整个mvc框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。前端控制...

前端控制器是整个mvc框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。前端控制器既可以使用filter实现(struts2采用这种方式),也可以使用servlet来实现(spring mvc框架)。

spring mvc DispatcherServlet之前端控制器架构详解

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的初始化

spring mvc DispatcherServlet之前端控制器架构详解

 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的代码之美。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。