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

原文地址:https://www.cnblogs.com/kindevil-zx/p/8569975.html