当前位置:   article > 正文

【SpringMVC源码剖析】 前奏:梦开始的地方

【SpringMVC源码剖析】 前奏:梦开始的地方

SpringMVC源码剖析

纵览:SpringMVC处理请求

本节作为SpringMVC源码剖析的基本,主要介绍以下三方面内容。

  • 1.核心DispatcherServlet的加载方式
  • 2.DispatcherServlet初始化过程
  • 3.SpringMVC接收请求并作出响应(粗粒度)
1.核心DispatcherServlet的加载方式
  • 1.1 传统的JavaWeb工程,以web.xml来配置加载Servlet容器的上下文,这显然有些麻烦。
  • 1.2 自从Servlet3.0+的出现,Spring-web模块提供了一种免配置文件,在如Tomcat(支持Servlet3.0+)这样的Servlet容器启动时,自动调用了实现的WebApplicationInitializer(全路径org.springframework.web.WebApplicationInitializer)接口的类的onStartup方法,并将容器的ServletContext往下传递。
public interface WebApplicationInitializer {
    void onStartup(ServletContext servletContext) throws ServletException;
}
  • 1
  • 2
  • 3
  • 1.3 从Spring-web模块的API中,找到子类AbstractAnnotationConfigDispatcherServletInitializer,它间接实现了WebApplicationInitializer接口,父类onStartup方法,首先创建RootWebApplicationContext并设置ContextLoaderListner监听器;其次,注册往servletContext注册DispatcherServlet实例。
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);

        registerDispatcherServlet(servletContext);
    }
    protected void registerDispatcherServlet(ServletContext servletContext) {
        //此处往servletContext添加DispatcherServlet实例
        //并为DispatcherServlet添加过滤器
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1.4 由于AbstractAnnotationConfigDispatcherServletInitializer是抽象类,Spring容器不能注入。它重写了父类创建根ApplicationContext与ServletApplicationContext方法,并抽象出两个方法(用来创建根ApplicationContext和ServletApplicationContext容器时,需要注入的组件字类节数组)。
public abstract class AbstractAnnotationConfigDispatcherServletInitializer
        extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createRootApplicationContext() {
            ...
    }
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        ...
    }
    //用来创建根ApplicationContext和ServletApplicationContext容器时,需要注入的组件字类节数组
    protected abstract Class<?>[] getRootConfigClasses();
    protected abstract Class<?>[] getServletConfigClasses();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1.5 因此 我们只需要编写SpringMVCInitializer来继承AbstractAnnotationConfigDispatcherServletInitializer类,让它来帮我们完成对DispatcherServlet实例的加载即可。
2.DispatcherServlet初始化过程
  • 2.1 DispatcherServlet有个静态块,用于加载同包下DispatcherServlet.properties策略文件的内容,代码如下
static {
        try {
            ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        }
        catch (IOException ex) {
            throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

DispatcherServlet.properties 策略文件的内容

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 2.2 DispatcherServlet作为一个HttpServlet类,在加载时,会调用init方法,查找或创建WebApplication容器并刷新操作(如果使用WebApplicationInitilazer加载方式,RootWebApplicationContext是已经存在了)
public abstract class HttpServletBean extends HttpServlet
        implements EnvironmentCapable, EnvironmentAware {


    @Override
    public final void init() throws ServletException {
        initServletBean();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

    @Override
    protected final void initServletBean() throws ServletException {

        this.webApplicationContext = initWebApplicationContext();

    }

    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

        if (this.webApplicationContext != null) {
            // A context instance was injected at construction time -> use it
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    ...
                    //刷新,调用cwac.refresh()方法
                    //触发了ContextRefreshListener.onApplicationEvent方法
                    //调用FrameworkServlet.this.onApplicationEvent方法
                    //调用子类,即DispatcherServlet.onRefresh方法
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        ...

        return wac;
    }

    public void onApplicationEvent(ContextRefreshedEvent event) {
        this.refreshEventReceived = true;
        onRefresh(event.getApplicationContext());
    }


    protected void onRefresh(ApplicationContext context) {
        // 调用子类,即DispatcherServlet.onRefresh方法
    }

    private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            FrameworkServlet.this.onApplicationEvent(event);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 2.3 调用DispatcherServlet.onRefresh方法,
@Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
        //判断Spring容器是否存在MultipartResolver,LocaleResolver,ThemeResolver,不存在打印日志
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        //默认行为,加载容器的hadlerMappings,handlerAdapters,handlerExceptionResolvers,并排序
        //不存在则加载策略文件
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        //容器中加载名为viewNameTranslator的解析器,
        //如果找不到,从策略文件加载第一个Translator,即
        //org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
        initRequestToViewNameTranslator(context);
        /默认行为,加载容器的viewResolvers,并排序
        //不存在则加载策略文件
        initViewResolvers(context);
        //容器中加载名为flashMapManager,
        //不存在的话,同上处理,找策略文件中第一个
        initFlashMapManager(context);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
3.SpringMVC接收请求并作出响应(粗粒度)
  • 3.1 DispatcherServlet作为httpServlet,当接收到请求时,会调用doService方法
@Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //往request设置setAttribute,将当前环境(本地化解析器,主题解析器等)给request,方法mvc框架其他组件可以获取到。
        ...
        try {
            //真实调用
            doDispatch(request, response);
        }
        finally {
            //为request设置WebAsyncManager属性
            //如果是同步请求,恢复请求前的属性
            ...
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 3.2 DispatcherServlet的doDistpach方法,才是接收请求的核心方法
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 {
                //判断request头部ContentType是否以"multipart/"开头,来标记是否为附件上传
                processedRequest = checkMultipart(request);
                //是否附件请求标记
                multipartRequestParsed = (processedRequest != request);

                //
                // 从handlerMappings(RequestMappingHanderMapping,策略文件的handlerMapping类已经过时了),获取HandlerExecutionChain
                //HandlerExecutionChain(包含一个handlerMethod,以及一堆handlerInterceptor)
                mappedHandler = getHandler(processedRequest);
                //找不到handlerMethod时,根据标是否抛出异常,还是直接response.sendError
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 根据handerMethod找到HandlerAdapter(RequestMappingHandlerAdapter)
                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;
                    }
                }
                // 调用所有HandlerInterceptor的preHandle()方法,如果返回false,不处理请求 
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 核心:::::通过RequestMappingHandlerAdapter的handle方法,处理请求逻辑,返回ModelView
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                //从viewNameTranslator中获取默认视图名,并设置到mv中
                applyDefaultViewName(request, mv);
                //调用所有HandlerInterceptor的postHandle()方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            //渲染请求结果
            //从ModelView中获取View
            //view.render(model,req,resp)渲染
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            //调用handerExecutionChain的afterCompletion
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            //调用handerExecutionChain的afterCompletion
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // 调用handerExecutionChain的applyAfterConcurrentHandlingStarted,实现异步拦截
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // 如果为附件请求,清理现场
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

注:从DispatcherServlet.properties知道默认的HandlerMapping实现类已经注解了@Deprecated,从注释头部得知,建议使用RequestMappingHandlerMapping类。Spring-Webmvc模块中,提供了@EnableWebMvc,它导入了@Import(DelegatingWebMvcConfiguration.class)DelegatingWebMvcConfiguration类,而DelegatingWebMvcConfiguration类继承了WebMvcConfigurationSupport,WebMvcConfigurationSupport又注入了RequestMappingHandlerMapping实例,如下面代码。所以可以通过注解@EnableWebMvc,向容器注入RequestMappingHandlerMapping实例。

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
        handlerMapping.setOrder(0);
        handlerMapping.setInterceptors(getInterceptors());
        //注入内容协商管理器handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());

        PathMatchConfigurer configurer = getPathMatchConfigurer();
        if (configurer.isUseSuffixPatternMatch() != null) {
            handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch());
        }
        if (configurer.isUseRegisteredSuffixPatternMatch() != null) {
            handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch());
        }
        if (configurer.isUseTrailingSlashMatch() != null) {
            handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch());
        }
        if (configurer.getPathMatcher() != null) {
            handlerMapping.setPathMatcher(configurer.getPathMatcher());
        }
        if (configurer.getUrlPathHelper() != null) {
            handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper());
        }

        return handlerMapping;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

注:RequestMappingHandlerMapping间接实现了InitializingBean接口,重写afterPropertiesSet,代码如下

    @Override
    public void afterPropertiesSet() {
        if (this.useRegisteredSuffixPatternMatch) {
            this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
        }
        //调用父类
        super.afterPropertiesSet();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
    @Override
    public void afterPropertiesSet() {
        initHandlerMethods();//初始化handlerMethods
    }
    protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }

        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));
        //收集所有注解了@Controller或@RequestMapping的方法
        for (String beanName : beanNames) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
                    isHandler(getApplicationContext().getType(beanName))){
                detectHandlerMethods(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

下节将细化介绍DispatcherServlet的getHandler(HttpServletRequest request)方法为入口进行源码剖析,将了解到

  • 如何获取到handlerMethod
  • 如何获取handlerInterceptor
  • 如何创建handlerExecutionChain
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/658188
推荐阅读
相关标签
  

闽ICP备14008679号