Spring MVC源码解析

具体参考:Spring MVC 原理探秘 - 一个请求的旅行过程

Spring MVC流程图

组件:

  • DispatcherServlet:Spring MVC 的核心组件,是请求的入口,负责协调各个组件工作。
  • HandlerMapping:内部维护了一些 <访问路径, 处理器> 映射,负责为请求找到合适的处理器。
  • HandlerAdapter:处理器的适配器。Spring 中的处理器的实现多变,比如用户处理器可以实现 Controller 接口,也可以用 @RequestMapping 注解将方法作为一个处理器等,这就导致 Spring 不止到怎么调用用户的处理器逻辑。所以这里需要一个处理器适配器,由处理器适配器去调用处理器的逻辑。
  • ViewResolver:视图解析器的用途不难理解,用于将视图名称解析为视图对象 View。
  • View:视图对象用于将模板渲染成 html 或其他类型的文件。比如 InternalResourceView 可将 jsp 渲染成 html。

Servlet

接口及其实现类结构

GenericServlet:实现了 Servlet 和 ServletConfig 两个接口,为这两个接口中的部分方法提供了简单的实现。比如该类实现了 Servlet 接口中的 void init(ServletConfig) 方法,并在方法体内调用了内部提供了一个无参的 init 方法,子类可覆盖该无参 init 方法。除此之外,GenericServlet 还实现了 ServletConfig 接口中的 getInitParameter 方法,用户可直接调用该方法获取到配置信息。

public abstract class GenericServlet 
    implements Servlet, ServletConfig, java.io.Serializable {

    // 省略部分代码

    private transient ServletConfig config;
    
    public GenericServlet() { } 
    
    /** 有参 init 方法 */
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        // 调用内部定义的无参 init 方法
        this.init();
    }

    /** 无参 init 方法,子类可覆盖该方法 */
    public void init() throws ServletException { }

    /** 未给 service 方法提供具体的实现 */
    public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    public void destroy() { }

    /** 通过 getInitParameter 可直接从 ServletConfig 实现类中获取配置信息 */
    public String getInitParameter(String name) {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameter(name);
    } 

    public ServletConfig getServletConfig() {
        return config;
    }
    
    // 省略部分代码
}

HttpServlet:这个类是和 HTTP 协议相关。该类的关注点在于怎么处理 HTTP 请求,比如其定义了 doGet 方法处理 GET 类型的请求,定义了 doPost 方法处理 POST 类型的请求等。我们若需要基于 Servlet 写 Web 应用,应继承该类,并覆盖指定的方法。doGet 和 doPost 等方法并不是处理的入口方法,所以这些方法需要由其他方法调用才行。

@Override
public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException {
    HttpServletRequest  request;
    HttpServletResponse response;
    
    if (!(req instanceof HttpServletRequest &&
            res instanceof HttpServletResponse)) {
        throw new ServletException("non-HTTP request or response");
    }

    request = (HttpServletRequest) req;
    response = (HttpServletResponse) res;

    // 调用重载方法,该重载方法接受 HttpServletRequest 和 HttpServletResponse 类型的参数
    service(request, response);
}

protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    String method = req.getMethod();

    // 处理 GET 请求
    if (method.equals(METHOD_GET)) {
        //获取Request的最后修改时间,若时间unknown,默认返回-1
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            // 调用 doGet 方法
            doGet(req, resp);
        } else {
            //上次服务器告诉它的文件最后修改时间
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            //判断是否已经修改更新
            if (ifModifiedSince < lastModified) {
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                //返回304状态,浏览器用缓存诗句
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }

    // 处理 HEAD 请求
    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    // 处理 POST 请求
    } else if (method.equals(METHOD_POST)) {
        // 调用 doPost 方法
        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 {
        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);
    }
}

DispatcherServlet 族谱

Aware

用于向 Spring “索要”一些框架中的信息。比如当某个 bean 实现了 ApplicationContextAware 接口时,Spring 在运行时会将当前的 ApplicationContext 实例通过接口方法 setApplicationContext 传给该 bean。

EnvironmentCapable

EnvironmentCapable 仅包含一个方法定义 getEnvironment,通过该方法可以获取到环境变量对象。通常可以EnvironmentCapable和 EnvironmentAware 接口配合使用。

如下这个例子:

public class EnvironmentHolder implements EnvironmentCapable, EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public Environment getEnvironment() {
        return environment;
    }
}

HttpServletBean

HttpServletBean 是 HttpServlet 抽象类的简单拓展。HttpServletBean 覆写了父类中的无参 init 方法,并在该方法中将 ServletConfig 里的配置信息设置到子类对象中,比如 DispatcherServlet。

FrameworkServlet

FrameworkServlet 是 Spring Web 框架中的一个基础类,该类会在初始化时创建一个容器。同时该类覆写了 doGet、doPost 等方法,并将所有类型的请求委托给 doService 方法去处理。doService 是一个抽象方法,需要子类实现。

DispatcherServlet

DispatcherServlet 主要的职责相信大家都比较清楚了,即协调各个组件工作。除此之外,DispatcherServlet 还有一个重要的事情要做,即初始化各种组件,比如 HandlerMapping、HandlerAdapter 等。

DispatcherServlet 源码简析

分析 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 {
            //检查是否是请求multipart如文件上传,如果是,则将通过multipartResolver解析
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 获取可处理当前请求的处理器 Handler,对应流程图中的步骤②
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 获取可执行处理器逻辑的适配器 HandlerAdapter,对应步骤③
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 处理 last-modified 消息头
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 执行拦截器 preHandle 方法(预处理)
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 调用处理器逻辑,对应步骤④
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            // 如果 controller 未返回 view 名称,这里生成默认的 view 名称
            applyDefaultViewName(processedRequest, mv);

            // 执行拦截器 preHandle 方法(后处理)
            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);
    }
    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 {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
        HandlerExecutionChain mappedHandler, ModelAndView mv, 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()) {
        // 渲染视图
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isDebugEnabled()) {...
    }

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

    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    Locale locale = this.localeResolver.resolveLocale(request);
    response.setLocale(locale);

    View view;
    /*
     * 若 mv 中的 view 是 String 类型,即处理器返回的是模板名称,
     * 这里将其解析为具体的 View 对象
     */ 
    if (mv.isReference()) {
        // 解析视图,对应步骤⑤
        view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                    "' in servlet with name '" + getServletName() + "'");
        }
    }
    else {
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                    "View object in servlet with name '" + getServletName() + "'");
        }
    }

    if (logger.isDebugEnabled()) {...}
    try {
        if (mv.getStatus() != null) {
            response.setStatus(mv.getStatus().value());
        }
        // 渲染视图,并将结果返回给用户。对应步骤⑥和⑦
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {...}
        throw ex;
    }
}

以上介绍了Servlet和DispatcherServlet方面的知识,从源码的角度分析了 DispatcherServlet 处理请求的过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值