SpringMVC与Web解读(二):Dispatcher

来源:互联网 发布:数据库 图标 编辑:程序博客网 时间:2024/06/05 22:44

在上一章中,主要讲了ContextLoaderListener对IoC容器在Web环境中的构建。本章讲另一个重点,DispatcherServlet

1.DispatcherServlet设计概述

DispatcherServlet作为一个前端控制器,所有的请求都要经过它来处理,进行转发、匹配、数据处理后,由页面进行展示。
在对完成ContextLoaderListener的初始化以后,Web容器开始初始化DispatcherServlet。DispatcherServlet会建立自己的上下文(Context)来持有SpringMVC的Bean对象,在建立这个自己持有的IoC容器的时候,会从ServletContext中得到根上下文(Root Context)来作为DispatcherServlet持有的上下文的双亲上下文。这个根上下文在上一章中有提到,是ContextLoader所设置的。
有了这个根上下文,在对自己持有的上下文进行初始化,并保存到ServletContext中,供以后使用。

1.1 DispatcherServlet类继承

先看类继承图:

这里写图片描述
DispatcherSerlvet通过继承FrameworkServlet和HttpServletBean而进程了HttpServlet,通过使用Serevlet AP来响应HTTP请求。

1.2 DispatcherServlet处理过程

从改图中,我们可以看出,其处理过程分为两个部分,一个是初始化,另一个则是doGet/doPost,处理请求的过程。doGet/doPost方法在进过Framework的processRequest()方法简单处理后,调用DispatcherServlet的doService方法,这个方法中封装了doDispatcher,这个方法是实现MVC模式的主要部分,也是接下来重点关注的部分。
这里写图片描述

2.DispatcherServlet的启动和初始化

作为一个Servlet的,开始时,Servlet的init方法被调用,加载Servlet中的设置。接下来,会执行DispatcherServlet持有的IoC容器的初始化过程,在这个初始化过程中,属于DispatcherServlet的上下文被建立起来,并设置为根上下文的子上下文。IoC容器getBean的时候,是会向双亲上下文getBaen。即根上下文的Bean可以被共享。上下文建立之后,和其它IoC容器一样通过refresh完成初始化。最后,DispatcherServlet给这个自己持有的上下文命名,并把它设置到Web容器的上下文中,这个名称和在web.xml中设置的DispatcherServlet的Servlet名称相关,从而保证了这个上下文在Web环境上下文体系的唯一性。

实现代码逻辑如上所述,这里不贴出来了。

Bean管理
这个时候IoC容器已经建立起来了,这个IoC容器是根上下文的子容器。对于一个Bean,系统首先到根容器查找,找不到之后,才回到DispatcherServlet所管理的IoC容器中去查找,这个是有IoC容器的getBean决定的。

2.1 Dispatcher Server的初始化

DispatcherServlet持有一个以自己Servlet命名的IoC容器。这个IoC容器是一个WebApplicationContext对象,这个IoC容器建立之后,意味着DispatcherServlet拥有自己的Bean定义空间,这位后来的XML文件来配置MVC中各个Bean创造了条件。自此之后,Web容器相关的加载已经完成。
接下来,是Sping MVC Dispatcher Server的初始化。
其调用关系如下:
这里写图片描述

其中初始化在initStrategies方法中完成。
其中,initHandlerMappings的作用是,为HTTP请求找到相应的Conteroller。其代码如下:

private void initHandlerMappings(ApplicationContext context) {   this.handlerMappings = null;   if (this.detectAllHandlerMappings) {      // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.      //找到所有在ApplicationContext中包含双亲上下文中的HandlerMappings。      Map<String, HandlerMapping> matchingBeans =            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);      if (!matchingBeans.isEmpty()) {         this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());         // We keep HandlerMappings in sorted order.       //排序            AnnotationAwareOrderComparator.sort(this.handlerMappings);      }   }   else { //根据名称从当前的IoC容器中通过getBean获取handlerMapping      try {         HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);         this.handlerMappings = Collections.singletonList(hm);      }      catch (NoSuchBeanDefinitionException ex) {         // Ignore, we'll add a default HandlerMapping later.      }   }   // Ensure we have at least one HandlerMapping, by registering   // a default HandlerMapping if no other mappings are found.   //要有至少一个HandlerMapping,如果没有找到,则设置一个默认的。   if (this.handlerMappings == null) {      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);      if (logger.isDebugEnabled()) {         logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");      }   }}

3. MVC处理HTTP分发请求

3.1 HandlerMapping的配置和设计原理

HandlerMapping也就是控制URL和相对应的处理方法的地方。在初始化的时候,在上下文环境中已定义的所有HandlerMapping都已经被加载在一个List中,并被排序(为什么排序)。这个List的每一个元素对应着一个具体的HandlerMapping的配置。一般来说,每一个HandlerMapping可以持有一系列从URL请求道Contorller的映射(对应/*等URL匹配规则)。
HandlerMapping的设计图:

这里写图片描述
其中,HandlerMapping的getHandler方法:

public interface HandlerMapping{    HandlerExecutionChain getHander(HttpServletRequest request);}public class HandlerExecutionChain {   private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);   private final Object handler; //HTTP请求对应的Handler   private HandlerInterceptor[] interceptors;   private List<HandlerInterceptor> interceptorList;   private int interceptorIndex = -1;//下面是一些增强方法   /**    * Create a new HandlerExecutionChain.    * @param handler the handler object to execute    */   public HandlerExecutionChain(Object handler) {      this(handler, (HandlerInterceptor[]) null);   }   /**    * Create a new HandlerExecutionChain.    * @param handler the handler object to execute    * @param interceptors the array of interceptors to apply    * (in the given order) before the handler itself executes    */   public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {      if (handler instanceof HandlerExecutionChain) {         HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;         this.handler = originalChain.getHandler();         this.interceptorList = new ArrayList<HandlerInterceptor>();         CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);         CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);      }      else {         this.handler = handler;         this.interceptors = interceptors;      }   }   /**    * Return the handler object to execute.    * @return the handler object (may be {@code null})    */   public Object getHandler() {      return this.handler;   }   public void addInterceptor(HandlerInterceptor interceptor) {      initInterceptorList().add(interceptor);   }   public void addInterceptors(HandlerInterceptor... interceptors) {      if (!ObjectUtils.isEmpty(interceptors)) {         CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList());      }   }   private List<HandlerInterceptor> initInterceptorList() {      if (this.interceptorList == null) {         this.interceptorList = new ArrayList<HandlerInterceptor>();         if (this.interceptors != null) {            // An interceptor array specified through the constructor            CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);         }      }      this.interceptors = null;      return this.interceptorList;   }   /**    * Return the array of interceptors to apply (in the given order).    * @return the array of HandlerInterceptors instances (may be {@code null})    */   public HandlerInterceptor[] getInterceptors() {      if (this.interceptors == null && this.interceptorList != null) {         this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);      }      return this.interceptors;   }   /**    * Apply preHandle methods of registered interceptors.    * @return {@code true} if the execution chain should proceed with the    * next interceptor or the handler itself. Else, DispatcherServlet assumes    * that this interceptor has already dealt with the response itself.    */   boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {      HandlerInterceptor[] interceptors = getInterceptors();      if (!ObjectUtils.isEmpty(interceptors)) {         for (int i = 0; i < interceptors.length; i++) {            HandlerInterceptor interceptor = interceptors[i];            if (!interceptor.preHandle(request, response, this.handler)) {               triggerAfterCompletion(request, response, null);               return false;            }            this.interceptorIndex = i;         }      }      return true;   }   /**    * Apply postHandle methods of registered interceptors.    */   void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {      HandlerInterceptor[] interceptors = getInterceptors();      if (!ObjectUtils.isEmpty(interceptors)) {         for (int i = interceptors.length - 1; i >= 0; i--) {            HandlerInterceptor interceptor = interceptors[i];            interceptor.postHandle(request, response, this.handler, mv);         }      }   }   /**    * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.    * Will just invoke afterCompletion for all interceptors whose preHandle invocation    * has successfully completed and returned true.    */   void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)         throws Exception {      HandlerInterceptor[] interceptors = getInterceptors();      if (!ObjectUtils.isEmpty(interceptors)) {         for (int i = this.interceptorIndex; i >= 0; i--) {            HandlerInterceptor interceptor = interceptors[i];            try {               interceptor.afterCompletion(request, response, this.handler, ex);            }            catch (Throwable ex2) {               logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);            }         }      }   }   /**    * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.    */   void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {      HandlerInterceptor[] interceptors = getInterceptors();      if (!ObjectUtils.isEmpty(interceptors)) {         for (int i = interceptors.length - 1; i >= 0; i--) {            if (interceptors[i] instanceof AsyncHandlerInterceptor) {               try {                  AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];                  asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);               }               catch (Throwable ex) {                  logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);               }            }         }      }   }   /**    * Delegates to the handler's {@code toString()}.    */   @Override   public String toString() {      Object handler = getHandler();      if (handler == null) {         return "HandlerExecutionChain with no handler";      }      StringBuilder sb = new StringBuilder();      sb.append("HandlerExecutionChain with handler [").append(handler).append("]");      HandlerInterceptor[] interceptors = getInterceptors();      if (!ObjectUtils.isEmpty(interceptors)) {         sb.append(" and ").append(interceptors.length).append(" interceptor");         if (interceptors.length > 1) {            sb.append("s");         }      }      return sb.toString();   }}}

在HandlerExecutionChain中设置了一个拦截器链,通过这个拦截器链中的拦截器,为handler对象提供功能的增强。

以SimpleURLHandlerMapping ,要做的就是根据URL映射的方式,注册Handle和Interceptor(拦截器),从而维护这样的一个映射的Map。
那么,SimplerURLHandlerMapping的注册Handler的过程就是我们接下来要关注的。

3.2 SimpleURLHandlerMapping注册Handler

···
public void initApplicationContext(){
super.initApplicationContext();
registerHandlers(this.urlMap);
}

//表层注册函数
protected void registerHandlers(Map

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {        Assert.notNull(urlPath, "URL path must not be null");        Assert.notNull(handler, "Handler object must not be null");        Object resolvedHandler = handler;        // 直接用Bean的名称进行映射        if (!this.lazyInitHandlers && handler instanceof String) {            String handlerName = (String) handler;            if (getApplicationContext().isSingleton(handlerName)) {                resolvedHandler = getApplicationContext().getBean(handlerName);            }        }        Object mappedHandler = this.handlerMap.get(urlPath);        if (mappedHandler != null) {            if (mappedHandler != resolvedHandler) {                throw new IllegalStateException(                        "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +                        "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");            }        }        else {            //"/"设置到rootHandler中            if (urlPath.equals("/")) {                if (logger.isInfoEnabled()) {                    logger.info("Root mapping to " + getHandlerDescription(handler));                }                setRootHandler(resolvedHandler);            }            //"/*"设置到defaultHandler当中            else if (urlPath.equals("/*")) {                if (logger.isInfoEnabled()) {                    logger.info("Default mapping to " + getHandlerDescription(handler));                }                setDefaultHandler(resolvedHandler);            }            else {                                //放入到一个Map当中                this.handlerMap.put(urlPath, resolvedHandler);                if (logger.isInfoEnabled()) {                    logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));                }            }        }    }

上面这个就是handlerMap了,其中保存了URL和COnteroller之间的映射关系。

3.3 使用HandlerMapping完成请求的映射处理

这个主要是HandleMapping中定义的getHandler方法了,只是通过URL匹配规则来获取持有Handler的HandlerExecutionChain。

3.4 SpingMCV对HTTP的请求的分发处理

这个无疑是我们所关注的重点啦。这里重新回到DispatcherSerlvelt。请求的分发在doService中的doDispatch完成。
以下是这个方法的过程,看似很长,其实只是,获取HandleExecutinChain,请求前置处理,处理,后置处理,视图呈现,结束。
以下是处理过程图:

这里写图片描述

以下是Spring技术内幕的代码注释图,不关注View的部分。

这里写图片描述
接下来,看下DispatcherServlet是如何获得一个Handler的,一个个找.

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {        for (HandlerMapping hm : this.handlerMappings) {            if (logger.isTraceEnabled()) {                logger.trace(                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");            }            HandlerExecutionChain handler = hm.getHandler(request);            if (handler != null) {                return handler;            }        }        return null;    }

视图呈现,在这里不关注。

原创粉丝点击