Spring MVC源码阅读笔记

刷了一遍spring mvc源码,记录一下,写的可能有点乱。

DispatcherServlet的核心方法为doDispatch,上图中的流程基本都在doDispatch中完成,下面贴上源码

    /**
     * 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) {
                    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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

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

                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                applyDefaultViewName(processedRequest, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

然后分析一下几个关键的节点

1.获取handler

HandlerExecutionChain  mappedHandler,这个为实际调度的对象,他的内部包含一个handler和一系列的拦截器,下面为官方注释

简单翻译一下,处理程序执行链,由handler和HandlerInterceptor组成。由HandlerMapping.getHandler方法返回这个对象。下面为类图

然后看一下如何获取HandlerExecutionChain  mappedHandler这个对象

 

 看代码只要匹配到第一个就返回了,然后看一下这个HandlerMapping.getHanlder方法

 翻译一下注释

返回此请求的处理程序和任何拦截器。可以根据请求URL、会话状态或实现类选择的任何因素进行选择。 返回的HandlerExecutionChain包含一个处理程序对象,而不是标记接口,因此处理程序不受任何约束。例如,可以编写HandlerAdapter来允许使用另一个框架的ni处理程序对象。如果没有找到匹配,则返回null。这不是一个错误。DispatcherServlet将查询所有已注册的HandlerMapping bean以查找匹配项,并且只有在没有找到处理程序时才判断是否存在错误。 

找一个比较常见的实现类RequestMappingHandlerMapping

先说结果RequestMappingHandlerMapping的getHanlder最终实现方式是通过@RequestMapping中的参数去匹配对应的方法,然后组装成Handler并加上对应的拦截器生成HandlerExecutionChain对象返回

RequestMappingHandlerMapping继承关系

RequestMappingHandlerMapping中并没有找到getHanlder这个方法,最后在AbstractHandlerMapping这个类中找到了实现,红框是重点关注的部分

(1)getHandlerInternal,这个主要是根据@RequestMapping中的参数匹配查找对应的handler,RequestMappingHandlerMapping的具体实现在父类AbstractHandlerMethodMapping

(2)getHandlerExecutionChain,这个方法是根据@RequestMapping中的参数匹配对应的拦截器然后和handler组装返回一个HandlerExecutionChain

小结一下,最常见的@Controller和@RequestMapping注册在RequestMappingHandlerMapping中,@RequestMapping中的参数进行匹配

其他的HandlerMapping还有很多,比如WebSocketHandlerMapping,WelcomePageHandlerMapping等,此处不展开

2.获取对应的HandlerAdapter 

实现方法为getHandlerAdapter

 关键代码为HandlerAdapter的supports,这是一个接口,所以找一个实现类,以RequestMappingHandlerAdapter为例,他的实现在父类AbstractHandlerMethodAdapter中,主要判断这个类是否是HandlerMethod类型

其他的实现类还有SimpleControllerHandlerAdapter(处理继承Controller接口的类),SimpleServletHandlerAdapter(处理Servlet类型的类)

3.获取到mappedHandler和handlerAdapter后,可以执行handlerAdapter的handle方法了,以RequestMappingHandlerAdapter为例

在执行真正的handler之前需要先执行mappedHandler中的applyPreHandle方法,这个主要是调用mappedHandler中对应拦截器的preHandle方法。

之后通过handlerAdapter执行mappedHandler中真正的handler

 

RequestMappingHandlerAdapter的handle方法有点绕,下面一点一点找

AbstractHandlerMethodAdapter.handle

AbstractHandlerMethodAdapter.handleInternal是一个抽象方法,在RequestMappingHandlerAdapter中实现

然后看RequestMappingHandlerAdapter.invokeHandlerMethod(代码有点长,一张图截不下)

/**
     * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
     * if view resolution is required.
     * @since 4.2
     * @see #createInvocableHandlerMethod(HandlerMethod)
     */
    @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            if (this.argumentResolvers != null) {
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }
            if (this.returnValueHandlers != null) {
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }
            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);

            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(logger, traceOn -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }

invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }

进入ServletInvocableHandlerMethod.invokeAndHandle

进入最关键的代码InvocableHandlerMethod.invokeForRequest(ServletInvocableHandlerMethod是InvocableHandlerMethod的子类)

先翻译一下注释

在给定请求的上下文中解析其参数值后调用该方法。 参数值通常通过HandlerMethodArgumentResolvers解析器解析。然而,providedArgs参数可以提供直接使用的参数值,即不需要参数解析。提供的参数值示例包括WebDataBinder、SessionStatus或抛出的异常实例。提供的参数值在参数解析器之前检查。 委托给getMethodArgumentValues并使用解析后的参数调用doInvoke。 

/**
     * Invoke the method after resolving its argument values in the context of the given request.
     * <p>Argument values are commonly resolved through
     * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
     * The {@code providedArgs} parameter however may supply argument values to be used directly,
     * i.e. without argument resolution. Examples of provided argument values include a
     * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
     * Provided argument values are checked before argument resolvers.
     * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
     * resolved arguments.
     * @param request the current request
     * @param mavContainer the ModelAndViewContainer for this request
     * @param providedArgs "given" arguments matched by type, not resolved
     * @return the raw value returned by the invoked method
     * @throws Exception raised if no suitable argument resolver can be found,
     * or if the method raised an exception
     * @see #getMethodArgumentValues
     * @see #doInvoke
     */
    @Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Arguments: " + Arrays.toString(args));
        }
        return doInvoke(args);
    }
InvocableHandlerMethod.getMethodArgumentValues方法,主要作用为获取参数值,参数值通过HandlerMethodArgumentResolver进行解析。
匹配方式可以参考RequestMappingHandlerAdapter.getDefaultArgumentResolvers方法中具体的HandlerMethodArgumentResolver。
这个HandlerMethodArgumentResolver其实也可以自行扩展,可以参考https://www.jianshu.com/p/40606baf49b8
    /**
     * Get the method argument values for the current request, checking the provided
     * argument values and falling back to the configured argument resolvers.
     * <p>The resulting array will be passed into {@link #doInvoke}.
     * @since 5.1.2
     */
    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }

        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            if (!this.resolvers.supportsParameter(parameter)) {
                throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
            }
            try {
                args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
            }
            catch (Exception ex) {
                // Leave stack trace for later, exception may actually be resolved and handled...
                if (logger.isDebugEnabled()) {
                    String exMsg = ex.getMessage();
                    if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, exMsg));
                    }
                }
                throw ex;
            }
        }
        return args;
    }

 获取到参数后,可以执行doInvoke方法了,这个比较简单,就是使用反射执行对应的方法

    /**
     * Invoke the handler method with the given argument values.
     */
    @Nullable
    protected Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(getBridgedMethod());
        try {
            return getBridgedMethod().invoke(getBean(), args);
        }
        catch (IllegalArgumentException ex) {
            assertTargetBean(getBridgedMethod(), getBean(), args);
            String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
            throw new IllegalStateException(formatInvokeError(text, args), ex);
        }
        catch (InvocationTargetException ex) {
            // Unwrap for HandlerExceptionResolvers ...
            Throwable targetException = ex.getTargetException();
            if (targetException instanceof RuntimeException) {
                throw (RuntimeException) targetException;
            }
            else if (targetException instanceof Error) {
                throw (Error) targetException;
            }
            else if (targetException instanceof Exception) {
                throw (Exception) targetException;
            }
            else {
                throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
            }
        }

小结一下RequestMappingHandlerAdapter的handle方法的核心为使用HandlerMethodArgumentResolver处理参数,之后使用反射方式执行controller中的method。

最后总结一下我们最常见的@RequestMapping和@Controller在Spring MVC中的执行过程

从RequestMappingHandlerMapping获取对应的HandlerExecutionChain mappedHandler

然后使用RequestMappingHandlerAdapter.handle 方法处理mappedHandler生成modelAndView

之后交由ViewResoler生成view,最后response根据view进行渲染

猜你喜欢

转载自www.cnblogs.com/lz-0011/p/12041381.html