小架构step系列19:请求和响应

深入理解SpringMVC请求响应机制

1 概述

作为Web程序,通用形式是发起HTTP请求并获取返回的结果,在这个过程中,需要把请求映射到代码的接口上,提供这种接口的类一般称为Controller,也就是需要把请求映射到Controller的接口方法上,把请求的参数映射到接口的参数中,并从接口返回接口处理的结果。

在后端渲染页面的场景中,返回的结果需要处理为视图View。而现在更普遍的是前后端分离,返回的结果一般处理为JSON格式的数据,前端拿到这种数据再进行处理和页面的渲染。

本文来了解一下这个请求和响应的过程。

2 原理

2.1 源码解析

在使用SpringBoot的时候,内嵌了一个tomcat服务器,做到了不需要感觉到有web服务器就能够开发web程序。内嵌tomcat服务器由tomcat-embed-core包提供,tomcat接收请求时,会调用到StandardWrapperValve的invoke()方法,下面的源码则从这段代码开始。

// tomcat接收请求时,会调用到StandardWrapperValve的invoke()方法
// 源码位置:org.apache.catalina.core.StandardWrapperValve(在tomcat-embed-core包)
public void invoke(Request request, Response response) throws IOException, ServletException {
    // 省略其它代码
    
    // 1. 组装Filter链
    ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    Container container = this.container;
    try {
        if ((servlet != null) && (filterChain != null)) {
            // Swallow output if needed
            if (context.getSwallowOutput()) {
                try {
                    SystemLogHandler.startCapture();
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                        filterChain.doFilter(request.getRequest(), response.getResponse());
                    }
                } finally {
                    String log = SystemLogHandler.stopCapture();
                    if (log != null && log.length() > 0) {
                        context.getLogger().info(log);
                    }
                }
            } else {
                if (request.isAsyncDispatching()) {
                    request.getAsyncContextInternal().doInternalDispatch();
                } else {
                    // 2. 递归调用Filter链,filterChain为ApplicationFilterChain
                    filterChain.doFilter(request.getRequest(), response.getResponse());
                }
            }

        }
    } 
    // 省略其它代码
}

// 源码位置:org.apache.catalina.core.ApplicationFilterChain
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    if (Globals.IS_SECURITY_ENABLED) {
        // 省略其它代码
    } else {
        // 3. 调用内部方法internalDoFilter()
        internalDoFilter(request, response);
    }
}

// 源码位置:org.apache.catalina.core.ApplicationFilterChain
private void internalDoFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
    // pos为当前filter在Filter链中的位置,n是filter的个数,也就是递归调Filter,到最后一个后就不满足pos<n条件
    if (pos < n) {
        // 取当前位置的Filter,同时pos加1方便下次取下一个Filter
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();

            if (request.isAsyncSupported() &&
                    "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
            }
            if (Globals.IS_SECURITY_ENABLED) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal = ((HttpServletRequest) req).getUserPrincipal();

                Object[] args = new Object[] { req, res, this };
                SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
            } else {
                // 调Filter的doFilter方法,注意Filter里一般要有filterChain.doFilter()才能触发下一个Filter执行
                // this就是filterChain
                filter.doFilter(request, response, this);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.filter"), e);
        }
        return;
    }

    // Filter正常结束后继续执行业务,如果不正常跑完Filter则在前面返回或抛异常了
    try {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(request);
            lastServicedResponse.set(response);
        }

        if (request.isAsyncSupported() && !servletSupportsAsync) {
            request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
        }
        // Use potentially wrapped request from this point
        if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) &&
                Globals.IS_SECURITY_ENABLED) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            Principal principal = ((HttpServletRequest) req).getUserPrincipal();
            Object[] args = new Object[] { req, res };
            SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal);
        } else {
            // 4. servlet为DispatcherServlet,调起servlet的service()方法
            servlet.service(request, response);
        }
    } catch (IOException | ServletException | RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        e = ExceptionUtils.unwrapInvocationTargetException(e);
        ExceptionUtils.handleThrowable(e);
        throw new ServletException(sm.getString("filterChain.servlet"), e);
    } finally {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(null);
            lastServicedResponse.set(null);
        }
    }
}

// 继承关系:DispatcherServlet < FrameworkServlet < HttpServletBean < HttpServlet
// DispatcherServlet本身没有重载service()方法,该方法由HttpServlet提供
// 源码位置:javax.servlet.http.HttpServlet
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    // 强制转了一下request和response的类型,也就是只有HttpServletRequest、HttpServletResponse类型才能往下处理
    HttpServletRequest request;
    HttpServletResponse response;
    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException(lStrings.getString("http.non_http"));
    }
    // 5. 调service接口,方法名称虽然相同但参数类型不一样
    service(request, response);
}

// 源码位置:javax.servlet.http.HttpServlet
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();
    
    // 根据HTTP的Method(GET、POST等)来分别处理,这里只看GET方法,其它方法类似
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            // 6. 处理GET请求
            doGet(req, resp);
        } else {
            // 省略部分代码
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);

    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);

    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);

    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req, resp);

    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req, resp);

    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

// FrameworkServlet重载了父类的doGet方法
// 源码位置:org.springframework.web.servlet.FrameworkServlet
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 7. 处理请求
    processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;

    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);

    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    initContextHolders(request, localeContext, requestAttributes);

    try {
        // 8. 处理请求
        doService(request, response);
    }
    catch (ServletException | IOException ex) {
        failureCause = ex;
        throw ex;
    }
    catch (Throwable ex) {
        failureCause = ex;
        throw new NestedServletException("Request processing failed", ex);
    }
    // 省略部分代码
}

// DispatcherServlet重载了父类的doService()方法
// 源码位置:org.springframework.web.servlet.DispatcherServlet
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 省略部分代码        Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap<>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }

    // Make framework objects available to handlers and view objects.
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

    if (this.flashMapManager != null) {
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    RequestPath previousRequestPath = null;
    if (this.parseRequestPath) {
        previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
        ServletRequestPathUtils.parseAndCache(request);
    }
    try {
        // 9. 处理请求
        doDispatch(request, response);
    }
    // 省略部分代码
}

// 源码位置:org.springframework.web.servlet.DispatcherServlet
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);

            // 10. 根据请求中的URL路径匹配到Controller提供的响应请求的http接口方法
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            String method = request.getMethod();
            boolean isGet = HttpMethod.GET.matches(method);
            if (isGet || HttpMethod.HEAD.matches(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

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

            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) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    // 省略部分代码
}

// 源码位置:org.springframework.web.servlet.DispatcherServlet
// DispatcherServlet在初始化的时候,通过Spring查找实现了org.springframework.web.servlet.HandlerMapping接口的所有类,
// 找到的类存放到handlerMappings变量中,大体上有下面6个是实现了HandlerMapping接口的类:
//     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
//     org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping
//     org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
//     org.springframework.web.servlet.function.support.RouterFunctionMapping
//     org.springframework.boot.autoconfigure.web.servlet.WelcomePageNotAcceptableHandlerMapping
//     org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            // 11. 这里重点看RequestMappingHandlerMapping对请求的处理
            //     RequestMappingHandlerMapping的getHandler()逻辑是根据请求里的接口路径匹配到Controller提供的http接口方法
            //     如果找到能处理请求的方法则返回,否则尝试下一个HandlerMapping
            //     返回的是封装了RequestMappingHandlerMapping的HandlerExecutionChain
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

// 回到DispatcherServlet的doDispatch()继续处理
// 源码位置:org.springframework.web.servlet.DispatcherServlet
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 != req
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值