ChenZhen 搜索
首页 标签 归档 留言板 友链 ChatGPT 提示库 AI工具导航网 🚇开往 关于我

SpringMVC源码分析

# 主题介绍 -- SpringMVC源码分析 ## 意义 - 通过阅读优秀的框架源码,可以深入理解框架的设计和实现原理,学习优秀的编程实践和设计模式。 - 框架通常是由经验丰富的开发人员设计和实现的,它们涉及到许多优秀的编程实践和设计模式。通过阅读框架源码,可以学习到这些实践和模式,并将其应用到自己的项目中,提升自己的代码水平和编程能力。 ## SpringMVC

ChenZhen 2024-04-23T16:54:38
cover

SpringMVC源码分析

主题介绍 -- SpringMVC源码分析

意义

  • 通过阅读优秀的框架源码,可以深入理解框架的设计和实现原理,学习优秀的编程实践和设计模式。

  • 框架通常是由经验丰富的开发人员设计和实现的,它们涉及到许多优秀的编程实践和设计模式。通过阅读框架源码,可以学习到这些实践和模式,并将其应用到自己的项目中,提升自己的代码水平和编程能力。

SpringMVC

Spring MVC是基于Servlet API构建的Web框架,是Spring框架的一部分。

Spring MVC是一个Web框架,平常所说的MVC是一种后端架构,而SpringMVC是基于MVC模式在 C [Controller]这一层上的一种实现框架,比如以前的Struts框架等等,再到早期的Servlet,都属于MVC里面的C这一层的实现技术。SpringMVC是对Servlet的封装。

Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程序,你还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 帮你简化了 Spring MVC 的很多配置,做到开箱即用

SpringMVC组件介绍

  1. DispatcherServletDispatcherServletSpringMVC中的前端控制器,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,负责接收request并将request转发给对应的处理组件。

  2. HandlerMappingHanlerMapping处理器映射是SpringMVC中完成urlController映射的组件。

  3. Handler:处理器,相当于是平常业务代码中每个请求对应的的controller类以及方法信息,是SpringMVC中负责处理request的组件。

  4. ModelAndView:是封装结果视图的组件。

  5. ViewResolver:视图解析器,解析ModelAndView对象,并返回对应的视图View给客户端。ViewResolver 的主要作用是将控制器返回的逻辑视图名(例如 "home"、"error" 等)解析为具体的视图对象(例如 JSPThymeleaf 模板等),然后由 DispatcherServlet 使用这些视图对象来渲染最终的视图内容。但在前后端分离的项目中,由于控制器不再返回视图名,而是直接返回数据,因此 ViewResolver 的传统用法变得多余。

SpringMVC处理流程:

  1. 首先,请求进入DispatcherServlet,由DispatcherServletHandlerMapping中提取对应的Handler

  2. 此时,只是获取到了对应的Handler,然后得去寻找对应的适配器,即:HandlerAdapter

  3. 拿到对应的HandlerAdapter后,开始调用对应的Handler处理业务逻辑,执行完成之后返回一个ModelAndView

  4. 这时候交给我们的ViewResolver,通过视图名称查找对应的视图,然后返回。

  5. 最后,渲染视图,返回渲染后的视图,响应给客户端。

web.xml配置

使用SpringMVC不需要我们写Servlet,但SpringMVC是封装了Servlet,提供 DispatcherServlet 来帮我们处理的。所以需要在 web.xml 配置 DispatcherServlet

可以看出 DispatcherServlet,映射的url/,所以所有的请求都会被它拦截,再处理给我们。

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <!--配置前端控制器-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!-- 加载SpringMVC配置文件 -->
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- 启动就加载这个Servlet -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    //省略其他配置...
</web-app>

SpringMVC工作机制

在容器初始化时会建立所有urlcontroller的对应关系,保存到Map<url,controller>中。

tomcat启动时会通知spring初始化容器(加载bean的定义信息和初始化所有单例bean),然后springmvc会遍历容器中的bean,获取每一个controller中的所有方法访问的url,然后将urlController保存到一个Map中;

这样就可以根据request快速定位到Controller

初始化

我们知道,Servlet初始化时,Servletinit()方法会被调用。Tomcat初始化servlet时,会来调用我们DispatcherServletinit()方法,

我们进入 DispatcherServlet中,发现并没有该方法,那么肯定在它继承的父类上。DispatcherServlet 继承于 FrameworkServlet,结果还是没找到,继续找它的父类 HttpServletBean

HttpServletBean

终于找到了,HttpServletBean 继承于 HttpServlet,我们来看下这个 init() 方法。

@Override
public final void init() throws ServletException {
    //获取配置web.xml中的参数
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
    	//设置配置相关代码
        .........
    }
    //重点:一个空方法,子类FrameworkServlet,重写了它,模板模式
    initServletBean();
}

FrameworkServlet

initServletBean()方法,就是一个初始化方法内主要是调用了 initWebApplicationContext() 初始化WebApplicationContext

@Override
protected final void initServletBean() throws ServletException {
    getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
    if (logger.isInfoEnabled()) {
        logger.info("Initializing Servlet '" + getServletName() + "'");
    }
    long startTime = System.currentTimeMillis();

    try {
        //重点:初始化WebApplicationContext
        this.webApplicationContext = initWebApplicationContext();
        //一个空方法,可以提供给以后的子类复写,做一些初始化的事情,暂时没有被复写
        initFrameworkServlet();
    }
    catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }

    //省略无关代码...
}

WebApplicationContext继承于 ApplicationContext,所以它是一个IoC容器。

这就相当于初始化了FrameworkServlet的属性WebApplicationContext,而子类DispatcherServlet继承了FrameworkServlet,相当于DispatcherServlet中有一个Spring的容器,DispatcherServlet收到请求后要根据请求的这一部分路径去找到Controller里面对应的方法,而ControllerBean对象,他就会到自己的Spring容器去寻找ControllerBean

用于管理 Web 应用程序中的 bean

下面分析 initWebApplicationContext()方法。

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    //有参数构造方法,传入webApplicationContext对象,就会进入该判断
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            //还没初始化过,容器的refresh()还没有调用
            if (!cwac.isActive()) {
                //设置父容器
                if (cwac.getParent() == null) {
                    cwac.setParent(rootContext);
                }
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    if (wac == null) {
        //获取ServletContext,之前通过setAttribute设置到了ServletContext中,现在通过getAttribute获取到
        wac = findWebApplicationContext();
    }
    if (wac == null) {
        //创建WebApplicationContext,设置环境environment、父容器,本地资源文件
        wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            //刷新,也是模板模式,空方法,让子类重写进行逻辑处理,而子类DispatcherServlet重写了它
            onRefresh(wac);
        }
    }

    //用setAttribute(),将容器设置到ServletContext中
    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}


//WebApplicationContext
public interface WebApplicationContext extends ApplicationContext {
    //...
}

FrameworkServlet类的职责是将 Spring 容器和 Servlet 容器关联起来的功能。

这个方法,除了初始化WebApplicationContext外,还调用了一个 onRefresh()方法,又是模板模式,空方法,让子类复写进行逻辑处理,例如子类DispatcherServlet重写了它

接来下,我们看子类 DispatcherServlet 复写的 onRefresh()方法。

DispatcherServlet

而对于 DispatcherServlet 来说,它初始化方法是 onRefresh()。

onRefresh() 方法,调用 initStrategies() 方法,进行各种组件的初始化工作。

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    //解析请求
    initMultipartResolver(context);
    //国际化
    initLocaleResolver(context);
    //主题
    initThemeResolver(context);

    //初始化HandlerMappings,Controller的方法和url映射关系
    initHandlerMappings(context);
    //初始化适配器,多样写法Controller的适配处理,实现最后返回都是ModelAndView
    initHandlerAdapters(context);
    //初始化异常处理器
    initHandlerExceptionResolvers(context);
    //初始化视图转发
    initRequestToViewNameTranslator(context);
    //初始化视图解析器,将ModelAndView保存的视图信息,转换为一个视图,输出数据
    initViewResolvers(context);
    //初始化映射处理器
    initFlashMapManager(context);
}

initHandlerMappings 初始化处理器映射

//处理器映射集合
@Nullable
private List<HandlerMapping> handlerMappings;
//一个开关,标识是否获取所有的处理器映射,如果为false,则搜寻指定名为的 handlerMapping 的 Bean实例
private boolean detectAllHandlerMappings = true;
//指定的Bean的名称
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

private void initHandlerMappings(ApplicationContext context) {
    //清空集合
    this.handlerMappings = null;
    
    //一个开关,默认为true,设置为false,才走else的逻辑
    if (this.detectAllHandlerMappings) {
        //重点:在容器中找到所有HandlerMapping
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        //找到了,进行排序,保证顺序
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        //指定搜寻指定名为 handlerMapping 的 HandlerMapping 实例
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }
    
    //也找不到映射关系,设置一个默认的
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }

    //配置文件名
    private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

    //从配置文件中获取配置的组件,其他组件找不到时,也是调用这个方法进行默认配置
    protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        //...
    }
}

如果找不到任何一个映射关系,会通过 getDefaultStrategies 方法,从配置文件中获取默认配置。其他组件找不到时,也是调用这个方法进行默认配置。

配置文件名:DispatcherServlet.properties。会加入默认的映射关系类 BeanNameUrlHandlerMapping 、 RequestMappingHandlerMapping。

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

HandlerAdapter 处理器适配器

HandlerAdapter 的初始化逻辑和上面的 HandlerMapping 基本一样。从容器中搜寻所有 HandlerAdapter 的实例。 如果找不到,则从配置文件中获取默认 的 HandlerAdapter。

//适配器集合
@Nullable
private List<HandlerAdapter> handlerAdapters;
//和上面HandlerMapping一样,一个开关,是否搜寻容器中所有的HandlerAdapter,如果为false,则搜寻指定名为 handlerAdapter 的Bean
private boolean detectAllHandlerAdapters = true;
//指定的HandlerAdapter实例
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";

private void initHandlerAdapters(ApplicationContext context) {
    //清空集合
    this.handlerAdapters = null;

    //也是一个开关,默认true,搜寻容器中所有的HandlerAdapter
    if (this.detectAllHandlerAdapters) {
        Map<String, HandlerAdapter> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        //找到了,进行排序,保证HandlerAdapter是有序的
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    }
    else {
        //指定找名为 handlerAdapter 的HandlerAdapter
        try {
            HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
            this.handlerAdapters = Collections.singletonList(ha);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerAdapter later.
        }
    }

    //没有找一个HandlerAdapter,从配置文件中获取默认的HandlerAdapter
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}

HandlerExceptionResolver 异常处理器

@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
//开关,是否梭巡所有的异常处理器,设置为false,就会找下面名为 handlerExceptionResolver 的Bean实例
private boolean detectAllHandlerExceptionResolvers = true;
//指定名为 handlerExceptionResolver 的实例
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";

private void initHandlerExceptionResolvers(ApplicationContext context) {
    //清空集合
    this.handlerExceptionResolvers = null;

    //开关,默认true
    if (this.detectAllHandlerExceptionResolvers) {
        //搜寻所有的异常处理器
        Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
        //搜寻到了
        if (!matchingBeans.isEmpty()) {
            this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
            //排序
            AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
        }
    }
    else {
        try {
            HandlerExceptionResolver her =
                    context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
            this.handlerExceptionResolvers = Collections.singletonList(her);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, no HandlerExceptionResolver is fine too.
        }
    }

    //一个异常处理器都没有,从配置文件中获取默认的
    if (this.handlerExceptionResolvers == null) {
        this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}

ViewResolver 视图解析器

视图解析器和上面的解析器逻辑一样,先有开关决定是搜寻容器中所有的,还是搜寻指定名称的。

//视图解析器集合
@Nullable
private List<ViewResolver> viewResolvers;
//开关
private boolean detectAllViewResolvers = true;
//指定名称
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

private void initViewResolvers(ApplicationContext context) {
    //清空集合
    this.viewResolvers = null;

    if (this.detectAllViewResolvers) {
        //搜寻所有视图解析器
        Map<String, ViewResolver> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.viewResolvers = new ArrayList<>(matchingBeans.values());
            //排序
            AnnotationAwareOrderComparator.sort(this.viewResolvers);
        }
    }
    else {
        try {
            //搜寻指定名为 viewResolver 的视图解析器Bean
            ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
            this.viewResolvers = Collections.singletonList(vr);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default ViewResolver later.
        }
    }

    //没有找到任何一个视图解析器,从配置文件中读取
    if (this.viewResolvers == null) {
        this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}

总结3个Servlet类的作用和职责

HttpServletBean

主要做一些初始化工作,解析 web.xml 中配置的参数到Servlet上,比如init-param中配置的参数。提供 initServletBean() 模板方法,给子类 FrameworkServlet实现。

FrameworkServlet

ServletSpringIoC容器关联。主要是初始化其中的 WebApplicationContext,它代表SpringMVC的上下文。 提供了 onRefresh() 模板方法,给子类 DispatcherServlet 实现,作为初始化入口方法。

DispatcherServlet

最后的子类,作为前端控制器,初始化各种组件,比如请求映射、视图解析、异常处理、请求处理等。 在这里插入图片描述

请求流程分析

当请求进入时,我们都知道会调用Servletservice() 方法,我们试着去 DispatchServlet 中搜索,发现没有。去到父类 FrameworkServlet 找到了,FrameworkServletservice()中区分成对应的回调方法调用 processRequest() 方法进行处理请求,而processRequest()方法里面又调用了doService()它是一个抽象方法,强制让子类进行复写。所以最终子类 DispatcherServlet 肯定会复写 doService() 方法。

DispatcherServlet doService()

doService() 方法中,主要的组件分发处理逻辑在 doDispatch() 方法中

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   	........
    try {
        //重点:主要的组件分发处理逻辑在 doDispatch() 方法
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }
}

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);

            //重点:找到本次请求的处理器以及拦截器, 
            mappedHandler = getHandler(processedRequest);
            //找不到处理器处理,响应404
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            //重点:找到本次请求中,处理器的适配器
            //获取处理器的适配器,因为有很多种处理器的实现方式,例如直接是Servlet作为处理器、实现Controller接口、使用Controller注解等,每个接口方法的返回值各式各样,所以这里使用了适配器模式,让适配器对处理器的返回值统一输出为ModelAndView。
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            .......

            //重点:处理前,责任链模式 回调拦截器的 preHandle() 方法,如果拦截了,则不继续往下走了
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            //随后,就调用适配器的 handle() 方法,进行适配,执行真正的handle业务代码,让适配器将处理器的结果转换成统一的ModelAndView。处理完后,也代表请求进过Controller处理完毕。
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            //如果找不到默认的视图,则设置默认的视图
            applyDefaultViewName(processedRequest, mv);
            //重点:处理完成,遍历调用处理器执行链中的拦截器的 postHandle() 后置处理方法,代表请求以被处理,但视图还未渲染
            mappedHandler.applyPostHandle(processedRequest, response, mv);

			//.....视图创建和渲染过程
        }
        
    }
}

getHandler() 搜寻本次请求的处理器对象

责任链模式,遍历handlerMappings集合,找到处理器和拦截器,会调用到getHandler()方法。最后将处理器和拦截器都封装到 HandlerExecutionChain 这个处理器执行链对象中。

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

getHandlerAdapter() 获取处理器对应的适配器

遍历调用适配器集合,调用supports()方法,询问每个适配器,是否支持当前的处理器。 如果返回true,则代表找到了,停止遍历,返回适配器。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            //责任链模式,遍历调用适配器集合,调用supports()方法,询问每个适配器,是否支持当前的处理器
            //如果返回true,则代表找到了,停止遍历,返回适配器
            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");
}

拦截器前置通知

遍历拦截器链,调用它的 preHandle() 方法,通知拦截器进行请求处理前的拦截和附加处理。 如果有一个拦截器返回false,代表拦截,则处理流程被中断,就是拦截了。

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
    	//遍历拦截器
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            //执行拦截器preHandle方法
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
    return true;
}

拦截器后置通知

逻辑还是遍历拦截器链,调用拦截器的 postHandle() 方法。

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
        throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    //遍历拦截器
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }
}
  • 初始化时
    • DispatchServlet 初始化,onRefresh 被调用,初始化处理器映射HandlerMappingHandlerAdapter适配器、 异常处理器、 视图解析器 等一系列组件。
  • 请求到达时
    • DispatchServletdoService() 被调用,根据请求的Url查找对应的处理器,包含我们的Controller和拦截器。
    • 根据处理器,找到对应的HandlerAdapter适配器,因为处理器的形式有很多,例如Servlet作为处理器、实现Controller接口,使用@Controller注解等,返回值都不一,就要使用适配器将结果都适配为ModelAndView
    • 执行适配器的处理方法前,先回调拦截器的前处理方法,如果拦截了,就不继续流程了。如果不拦截,则继续走,调用适配器的处理方法,在处理方法中,会调用处理器进行处理,就调用到我们的Controller。执行完后,再回调拦截器的后处理回调方法。
    • 获取到 ModelAndView 后,交给视图解析器ViewResolver,进行解析视图名称为具体视图实例后,再进行视图和数据的渲染返回给客户端,并回调拦截器视图渲染完后的回调方法。

请求到来时,从DispatchServlet前端控制器开始,通过url查找处理器,查找处理器对应的适配器,执行适配器的处理方法,返回ModelAndView。视图处理器解析ModelAndView,生成对应的视图对象,渲染视图和数据,并返回给客户端。

© 版权声明
😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗😚😙😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😏😒🙄😬🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵🤯🤠🥳😎🤓🧐😕😟🙁☹️😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬