SpringMVC原理分析(十一)--请求执行流程

当服务器接收到请求时,Tomcat会调用DispatcherServlet#doDispatch统一处理请求

java 复制代码
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);
            // 1.获取Handler处理器对象
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
            // 2.获取对应的HandlerAdapter对象
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            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;
                }
            }
            // 3.调用HandlerInterceptor前置处理请求
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 4.真正处理请求
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            applyDefaultViewName(processedRequest, mv);
            // 5.调用HandlerInterceptor后置处理请求
            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);
        }
        // 6.处理请求结果
        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()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

doDispatch的核心逻辑如下:

1.获取Handler处理器对象

遍历默认的(或配置在容器中的)handlerMappings,根据请求路径匹配某个HandlerMapping中的Handler,并封装成HandlerExecutionChain返回

2.获取对应的HandlerAdapter对象

遍历默认的(或配置在容器中的)handlerAdapters,根据HandlerAdpater接口中的supports方法判断该Handler能否被此handlerAdapter处理,如果可以处理即返回

java 复制代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

即不同的HandlerAdpater实现类可以处理不同类型的Handler,DispatcherServlet.properties中的默认配置是HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter及HandlerFunctionAdapter

1)HttpRequestHandlerAdapter能处理实现了HttpRequestHandler接口的Handler

java 复制代码
public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
}

2)SimpleControllerHandlerAdapter能处理实现了Controller接口的Handler

java 复制代码
public boolean supports(Object handler) {
    return (handler instanceof Controller);
}

3)RequestMappingHandlerAdapter能处理HandlerMethod类型的Handler

java 复制代码
public final boolean supports(Object handler) {
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

protected boolean supportsInternal(HandlerMethod handlerMethod) {
    return true;
}

4)HandlerFunctionAdapter能处理实现了HandlerFunction接口的Handler

java 复制代码
public boolean supports(Object handler) {
    return handler instanceof HandlerFunction;
}

3.调用HandlerInterceptor前置处理请求

获取Handler的过程中会将Handler对象封装为HandlerExecutionChain对象,其中包含了Handler和HandlerInterceptor两部分,HandlerInterceptor用于对处理器进行增强

HandlerInterceptor是如何添加进来的呢?我们看下AbstractHandlerMapping#initApplicationContext

java 复制代码
protected void initApplicationContext() throws BeansException {
    // 1.通过子类继承扩展
    extendInterceptors(this.interceptors);
    // 2.查找容器中的MappedInterceptor
    detectMappedInterceptors(this.adaptedInterceptors);
    // 3.将interceptors统一添加到adaptedInterceptors中
    initInterceptors();
}

protected void extendInterceptors(List<Object> interceptors) {}

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
    mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(
        obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

AbstractHandlerMapping是所有默认HandlerMapping的父类,如下图所示:

因此这些HandlerMapping在初始化时都会调用到AbstractHandlerMapping的initApplicationContext注册HandlerInterceptor,从源码看出,注册方式有2种:1)自定义HandlerMapping子类重写extendInterceptors方法;2)在容器中添加HandlerInterceptor的组件

然后再获取Handler之后调用getHandlerExecutionChain将Handler和HandlerInterceptor封装成HandlerExecutionChain对象,源码如下:

java 复制代码
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                                   (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                // HandlerExecutionChain添加匹配的HandlerInterceptor
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

在步骤3中会依次执行这些HandlerInterceptor的preHandle做前置处理逻辑

4.调用HandlerAdapter的handle方法真正的处理请求

此时会调用HandlerAdapter的具体实现类去执行处理方法,这里以最常用的RequestMappingHandlerAdapter为例说明,源码见RequestMappingHandlerAdapter#handleInternal

java 复制代码
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ModelAndView mav;
    checkRequest(request);

    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                // 执行请求
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // 执行请求
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // 执行请求
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }
    }

    return mav;
}

核心方法是调用RequestMappingHandlerAdapter#invokeHandlerMethod

java 复制代码
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,这个对象中聚合了执行方法需要的所有组件
        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);

        // 省略部分代码...

        // 执行处理器方法
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        // 返回ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        // 标记请求处理完成
        webRequest.requestCompleted();
    }
}

在invokeHandlerMethod中,具体执行处理器方法的是ServletInvocableHandlerMethod对象,它需要添加一些组件配合完成请求的处理,这些组件分别有参数名称解析器、数据绑定工厂、参数解析器及返回值解析器

invocableMethod.invokeAndHandle执行控制器方法,源码如下:

java 复制代码
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
    // 调用控制器方法执行请求,获取响应对象
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    setResponseStatus(webRequest);

    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 通过返回值处理器处理响应对象
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

再通过invokeForRequest解析参数后,调用控制器方法执行请求

java 复制代码
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);
}

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);
        // 从给定参数中寻找,如果能匹配到就不通过参数解析器进行解析了
        // providedArgs一般为空,invocableMethod.invokeAndHandle调用时可以传入一些参数
        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        // 判断参数解析器能够支持此参数,这里的参数解析器是HandlerMethodArgumentResolverComposite组合器,会依次匹配每个参数解析器
        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) {
            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()通过方法反射调用目标控制器方法

java 复制代码
protected Object doInvoke(Object... args) throws Exception {
    // 如果不是public修饰的方法,则setAccessible(true)
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // 通过方法反射调用,getBridgedMethod如果不是桥接的方法,返回的就是方法本身
        return getBridgedMethod().invoke(getBean(), args);
    }
    // 省略异常处理代码...
}

5.调用HandlerInterceptor后置处理请求

与步骤3类似,此时会依次执行这些HandlerInterceptor的postHandle做后置处理逻辑

6.处理请求结果

处理请求结果时会先判断上述执行过程中是否出现异常,如果有异常,则处理异常,返回异常处理后的ModelAndView,然后再判断是否需要进行视图渲染

java 复制代码
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {
    boolean errorView = false;

    // 如果执行过程中有异常
    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            // 处理异常
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    if (mv != null && !mv.wasCleared()) {
        // 如果需要渲染视图,则走mvc的流程
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        return;
    }

    if (mappedHandler != null) {
        // 调用方法拦截器HandlerInterceptor的afterCompletion方法
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}
相关推荐
色空大师9 分钟前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)9 分钟前
设计模式-创建型-建造者模式
java·设计模式·建造者模式
2202_7544215427 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
蓝染-惣右介29 分钟前
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
java·数据库·tomcat·mybatis
小林想被监督学习30 分钟前
idea怎么打开两个窗口,运行两个项目
java·ide·intellij-idea
HoneyMoose32 分钟前
IDEA 2024.3 版本更新主要功能介绍
java·ide·intellij-idea
我只会发热34 分钟前
Java SE 与 Java EE:基础与进阶的探索之旅
java·开发语言·java-ee
是老余35 分钟前
本地可运行,jar包运行错误【解决实例】:通过IDEA的maven package打包多模块项目
java·maven·intellij-idea·jar
crazy_wsp35 分钟前
IDEA怎么定位java类所用maven依赖版本及引用位置
java·maven·intellij-idea
.Ayang38 分钟前
tomcat 后台部署 war 包 getshell
java·计算机网络·安全·web安全·网络安全·tomcat·网络攻击模型