SpringWeb MVC加载源码浅析

1.Spring mvc,依靠DispatcherServlet请求分发器来处理指定URL的请求,他本身就直接或间接继承或者实现了
ApplicationContextAware、HttpServletBean、HttpServlet,也就是说明这个类同时具备了请求分发、ioc处理以及视图解析的功能。下面请看关系图:
SpringWeb MVC加载源码浅析_第1张图片
下面请看部分属性

   //请求url 解析,通过请求获取所属Handler也就是控制器
   private List<HandlerMapping> handlerMappings;
   //适配器
    private List<HandlerAdapter> handlerAdapters;
  //视图解析器
    private List<ViewResolver> viewResolvers;
2.基于过程看程序。通常一个请求过来,tomcat会根据web.xml
配置的servletMapping作用范围找到DispatherServlet,又因其本身就是Servlet故会执行doService(request,reponse)方法,
这个时候就会基于requset查找对应映射的Handler,然后根据handler查找对应的适配器,
不同的适配器自然具有不同的功能HttpRequestHandlerAdapter(普通的servlet),
SimpleControllerHandlerAdapter,SimpleServletHandlerAdapter(简单的servlet),RequestMappingHandler(注解使用)

SpringWeb MVC加载源码浅析_第2张图片

3.加载控制的方式有两种,一种是基于注解的,则Spring在初始化org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping的时候会向AbstractHandlerMethodMapping.register注册 意url为key以包加类加方法名为值得HandlerMethond信息,如图
SpringWeb MVC加载源码浅析_第3张图片
这里用到了读写锁
SpringWeb MVC加载源码浅析_第4张图片
因此AbstractHandlerMethodMapping保存所有mvc的方法注解信息,而AbstractHandlerMethodAdapter自然也可以根据handler获得;而普通方式通过xml方式的配置中除了要在xml声明handler即控制器外,还要声明一个存储映射关系的SimpleUrlHandlerMapping,同时还配置一个SimpleControllerHandlerAdapter适配器,这样才能正常完成请求映射,而spring注解则会轻松帮忙默认实现,所以spring的方便性得以体现。当然视图解析器这一方面无论通过哪种方式都要在声明,否则会出现一个视图解析的问题。
4.当一个请求过来首先要获取handler,那么如何获取呢?分发器会获取所有的HandlerMapping并遍历判断当属哪一个Mapping映射之下。SpringWeb MVC加载源码浅析_第5张图片
SpringWeb MVC加载源码浅析_第6张图片
4.当得到一个handler之后,又是怎样获取相关的适配器呢?如下图依然会遍历容器内的所有适配器,并且调用support方法判断是否支持,这里代码相对简单就是判断是否实现了对应适配器的接口Handler;
SpringWeb MVC加载源码浅析_第7张图片
但是在这句代码后我们的spring并未把handler而是返回了一个包含拦截器的HandlerExecutionChain对象,而
获取拦截也是同理,即获取分发器的adaptedInterceptors并进行路径匹配判断返回,以下是该类的成员属性

    private final Object handler;
    private HandlerInterceptor[] interceptors;//这里包含疑惑,既然已经有了拦截器数组,为啥还要拦截器list?
    private List<HandlerInterceptor> interceptorList;
    private int interceptorIndex;

5.得到对应适配器后,会让不同的适配器来处理handler.handle 而在这个过程中,HandlerExecutionChain则会在handle前中后()调用实现拦截器的功能,这里以为例解析handle源码,代码看上去简单,其实实现还是要推敲的这里不做介绍
SpringWeb MVC加载源码浅析_第8张图片

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        this.checkRequest(request);
        ModelAndView mav;
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                //利用反射机制执行控制器的目标方法
                    mav = this.invokeHandlerMethod(request, response, handlerMethod);
                }
            } else {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }

        if (!response.containsHeader("Cache-Control")) {
            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            } else {
                this.prepareResponse(response);
            }
        }

        return mav;

6.在执行了目标handler方法后会解析对应的视图解析器,然后渲染数据,当出现异常则会标记异常,并在 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException)传入标记,并查询分发器中的异常拦截器,并做对应处理返回错误视图view
SpringWeb MVC加载源码浅析_第9张图片
SpringWeb MVC加载源码浅析_第10张图片

   ModelAndView exMv = null;
        Iterator var6 = this.handlerExceptionResolvers.iterator();

        while(var6.hasNext()) {
            HandlerExceptionResolver handlerExceptionResolver = (HandlerExceptionResolver)var6.next();
            exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
            if (exMv != null) {
                break;
            }
        }

你可能感兴趣的:(编程人生,框架功能)