SpringMVC源码从入门到放弃-DispatcherServlet

本系列文章主要对SpringMVC源码做详细介绍,面向对Spring有所了解的Java程序员程序员

本文拟解惑几个问题
1.http请求如何映射到Controller的
2.Controller是如何被执行的web

DispatcherServlet

在有SpringMVC以前,咱们要对外提供http接口,那么咱们须要编写HttpServlet,并在web.xml中配置http请求到HttpServlet的映射关系
在有SpringMVC以后,开发人员开始写Controller并用注解@RequestMapping("\test")定义http请求到Controller.method()的映射关系spring

从HttpServlet到Controller实际上是由于SpringMVC对HttpServlet进行了一层封装,对外提供一个接收全部请求的HttpServlet(DispatcherServlet),Spring把Controller加了@RequestMapping的方法定义为HandlerMethod,由DispatcherServlet统一分发http请求到对应的HandlerMethod去处理mvc

因此SpringMVC项目咱们都要在web.xml中配上全部请求到DispatcherServlet的映射app

<servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

DispatcherServlet的本质是一个HttpServlet

核心的方法有框架

@Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            doDispatch(request, response);
        }

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

父类FrameworkServlet重写了HttpServlet的doGet()、doPost()等方法,最后都会调用DispatcherServlet的doService()方法,而后核心的执行流程在doDispatch()方法中ide

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                //由HandlerMapping找处理该请求的HandlerMethod和拦截该请求的HandlerInterceptor,包装成HandlerExecutionChain
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 找到该HandlerMethod的HandlerAdapter(具体的方法调用流程)
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());      
                                
                                //执行HandlerInterceptor
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Actually invoke the handler. 实际调用HandlerMethod
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        

                //执行HandlerInterceptor
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            
                        //返回渲染视图
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        
        }

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

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (ha.supports(handler)) {
                return ha;
            }
        }
    }

这里涉及到两个核心的类
1.HandlerMappingthis

Interface to be implemented by objects that define a mapping between
requests and handler objects.
2.HandlerAdapterurl

  • MVC framework SPI, allowing parameterization of the core MVC workflow.
  • Interface that must be implemented for each handler type to handle a request.

  • This interface is used to allow the {@link DispatcherServlet} to be indefinitely
  • extensible. The {@code DispatcherServlet} accesses all installed handlers through
  • this interface, meaning that it does not contain code specific to any handler type.

HandlerMapping

如官方文档里提到的,HandlerMapping定义了request和handler的映射关系,通俗点来讲就是url对应的是哪一个HandlerMethod

public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

核心方法返回HandlerExecutionChain,包装了当前请求须要执行的Handler和interceptors

public class HandlerExecutionChain {

    private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

    private final Object handler;

    private HandlerInterceptor[] interceptors;

在DispatcherServlet.getHandler中
遍历容器中全部的HandlerMapping,为当前请求找到最匹配的HandlerMethod,包装成HandlerExecutionChain,SpringMVC默认有不少HandlerMapping实现策略,每一个HandlerMapping中注册着不一样的HandlerMethod映射关系

咱们项目中默认对于Controller+@RequestMapping形式的HandlerMapping实现类为RequestMappingHandlerMapping
他的父类的内部中维护了请求和HandlerMethod的映射关系

class MappingRegistry {
        private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();

        private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();

下一期咱们将详细阐述HandlerMapping


HandlerAdapter

DispatcherServlet.getHandlerAdapter(Object handler)方法为当前handler找到合适的HandlerAdapter
从文档定义能够看出,HandlerAdapter定义了一个handler执行的流程,大体包括如下流程
1.请求参数解析成调用handler的参数
2.经过反射调用handler
3.处理handler的返回值

Spring上下文中有3个默认的HandlerAdapter实现,@RequestMapping定义的handler默认由RequestMappingHandlerAdapter处理

handler被交由RequestMappingHandlerAdapter的handle(HttpServletRequest request, HttpServletResponse response, Object handler)方法执行
通过层层调用,在invokeHandlerMethod()中定义了执行流程

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 invocableMethod = createInvocableHandlerMethod(handlerMethod);
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);//参数解析
            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);
        
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }

咱们先来看看invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
                //执行调用
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);

    
        try {//处理返回值
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }

    }

    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
                //获取参数
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        //
        Object returnValue = doInvoke(args);
        
        return returnValue;
    }

最后实际调用Controller的方法的就是doInvoke中,传入参数,利用反射进行调用

protected Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(getBridgedMethod());
        try {
            return getBridgedMethod().invoke(getBean(), args);
        }

以上就是一次htpp请求的调用过程,下一篇文章咱们将详细阐述handleMethod的注册过程

继承结构

文章的末尾咱们来看看DispatcherServlet的继承结构

DispatcherServlet

用于HTTP请求handler/controllers的中央调度程序,例如用于Web UI controllers或基于HTTP的远程服务导出程序。调度注册的handlers以处理Web请求,提供方便的url映射和异常处理功能。
这个servlet很是灵活:它能够在任何工做流程中使用,只要实现了合适的adapter类。它提供了如下功能,将其与其余请求驱动的Web MVC框架区分开来:
1.基于JavaBeans配置机制。
2.它可使用任何HandlerMapping实现 - 预先构建或做为应用程序的一部分提供 - 控制分发 requests 到 handler objects。默认是 BeanNameUrlHandlerMapping和 RequestMappingHandlerMapping。HandlerMapping对象能够定义为servlet应用程序上下文中的bean,实现HandlerMapping接口,覆盖默认的HandlerMapping(若是存在)。
3.它可使用任何HandlerAdapter; 这容许使用任何处理程序接口。默认适配器HttpRequestHandlerAdapter, 默认 RequestMappingHandlerAdapter 也会被注册。HandlerAdapter对象能够在应用程序上下文中做为bean添加,并覆盖默认的HandlerAdapter。
4。调度程序的exception解决策略能够经过一个HandlerExceptionResolver例如映射到错误页面的特定例外来指定 。默认的是 ExceptionHandlerExceptionResolver, ResponseStatusExceptionResolver和 DefaultHandlerExceptionResolver。这些HandlerExceptionResolvers能够经过应用程序上下文重写。
5.其视图解析策略能够经过ViewResolver 实现来指定,将符号视图名称解析为视图对象。默认是 InternalResourceViewResolver。能够在应用程序上下文中将ViewResolver对象添加为bean,覆盖默认的ViewResolver。

注意:@RequestMapping只有在调度程序中存在相应HandlerMapping和HandlerAdapter时才会处理。 这是默认状况。可是,若是您正在定义自定义HandlerMappings 或者HandlerAdapters,那么您须要确保相应的自定义 RequestMappingHandlerMapping和/或RequestMappingHandlerAdapter 定义 - 只要您打算使用@RequestMapping。

Web应用程序能够定义任意数量的DispatcherServlet。 每一个servlet将在其本身的名称空间中运行,使用映射,处理程序等加载其本身的应用程序上下文。只有ContextLoaderListener共享根据应用程序上下文。

核心方法

/**
     * Process the actual dispatching to the handler.
     * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
     * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
     * to find the first that supports the handler class.
     * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
     * themselves to decide which methods are acceptable.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     */
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

FrameworkServlet

相关文章
相关标签/搜索