SpringMVC 基础运行原理

Spring MVC 框架为展现层提供的基于MVC设计理念的优秀的web框架,是目前最主流的MVC框架之一。
关于他的运行流程之前没有在意,这次作为博客的第一篇文章仔细的看一看:
这里我以基于注解的HelloWorld级程序为例进行分析

一:首先就是Spring MVC在web.xml中的配置信息,也就是DispatcherServlet,在相应配置的情况下,对请求进行拦截,然后把这个请求信息交给DIspatcherServlet处理。(servlet-mapping中的url-pattern),关于DIspatcherServlet其他的方法不进行介绍,这个不是本篇文章的重点,主要是doDispatch方法。

    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;

                // ①:关键点一:获取handler
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // ②:关键点二:通过HandlerAdapter对Handler进行封装
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // 获取Http请求方式
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    //return -1
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                try {
                // ③:重点三:以统一的适配器接口、通过反射调用目标方法,返回ModelAndView
                    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);
            }
        }
    }

①:第一个重点:通过遍历已注册的HandlerMapping查找对应的handle。
handlerMappings中有几个比较常见:
1)BeanNameUrlHandlerMapping:通过对比Url和bean的name找到对应的对象
2)SimpleUrlHandlerMapping:与上面一样,功能更多
3)DefaultAnnotationHandlerMapping:主要关于注解的方式,已过时
4)RequestMappingHandlerMapping:取代上面的。

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() + "'");
            }
            //getHandler(request)方法在下方
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                //这时候就是已经找到对应的handler类了
                return handler;
            }
        }
        return null;
    }
--------------------------------------------------------------------------------
@Override
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //通过urlPath以及handlerMap来获取对应handler,这是一个抽象的方法,由具体的HandlerMapper来实现
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        return getHandlerExecutionChain(handler, request);
    }

②:第二个重点:通过HandlerAdapter对Handler进行封装。

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        //遍历所有的handlerAdapters,判断是否支持这个handler
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
----------------------------------------------------------------------------------------
//以第一个HandlerAdapter 为例HttpRequestHandlerAdapter:
public class HttpRequestHandlerAdapter implements HandlerAdapter {

    @Override
    public boolean supports(Object handler) {
        //就是判断这个handler是否是当前迭代类型的。如果是则直接返回这个Adapter类
        return (handler instanceof HttpRequestHandler);
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        ((HttpRequestHandler) handler).handleRequest(request, response);
        return null;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

③:第三个重点:以统一的适配器接口调用目标方法、返回ModelAndView

@Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //目标handler
        Class clazz = ClassUtils.getUserClass(handler);
        Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
        if (annotatedWithSessionAttributes == null) {
            annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
            this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
        }

        if (annotatedWithSessionAttributes) {
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
            // Prepare cached set of session attributes names.
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandlerMethod(request, response, handler);
                }
            }
        }
        //--
        return invokeHandlerMethod(request, response, handler);
    }
----------------------------------------------------------------------------------------
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
        //☆
        Method handlerMethod = methodResolver.resolveHandlerMethod(request);
        ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        ExtendedModelMap implicitModel = new BindingAwareModelMap();

        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
        ModelAndView mav =
                methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
        methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
        return mav;
    }
-----------------------------------------------------------------------------------
public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {
    String lookupPath = urlPathHelper.getLookupPathForRequest(request);
    Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath);
    Map<RequestSpecificMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestSpecificMappingInfo, Method>();
    Set<String> allowedMethods = new LinkedHashSet<String>(7);
    String resolvedMethodName = null;
    //遍历当前handler中所有的方法
    for (Method handlerMethod : getHandlerMethods()) {
    RequestSpecificMappingInfo mappingInfo = new RequestSpecificMappingInfo(this.mappings.get(handlerMethod));
    boolean match = false;
............................................

④:第四个重点:渲染视图:这个东西还是比较复杂的,我这里只需知道两点
1)DispatcherServlet借助ViewResoler完成逻辑视图名到真实视图对象的解析
2)得到真实视图对象 View 后, DispatcherServlet使用这个 View 对ModelAndView中的模型数据进行视图渲染。

你可能感兴趣的:(A1)