• SpringMVC源码从入门到放弃-DispatcherServlet


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

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

    DispatcherServlet

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

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

    所以SpringMVC项目我们都要在web.xml中配上所有请求到DispatcherServlet的映射

      <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()方法中

    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.HandlerMapping

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

    • 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

  • 相关阅读:
    数据库范式
    SQL基础
    JAVA流
    response.getWriter()和jsp中的out对象的区别
    JAVA排序(冒泡,直接选择,反转)
    Collections类常用方法
    JAVA集合
    JAVA面向对象(重载,重写 常用的 toString/equals)
    Java面向对象一(封装 继承 多态 类 对象 方法)
    JAVA基础
  • 原文地址:https://www.cnblogs.com/kindevil-zx/p/8569975.html
Copyright © 2020-2023  润新知