SpringMVC源码深刻解析

感悟

经过前面SpringAOP源码深度解析SpringIOC源码深度解析加上本文的SpringMVC的源码阅读,我从中收获不少,学习了各类设计模式,各类抽象思想,以及各类底层原理,好比动态代理,反射等等,虽然前前先后后大概花了一个多月,可是我不后悔,并不以为是浪费时间。php

本文比较长,我花了三天的时间完成本文,可是仍是水平有限,不可能面面俱到,当中也可能会有错的,还请读者指出,一块儿交流一块儿进步。html

本文采用的源码版本是5.2.x,一样,为了能收获更多,还请读者打开Spring的源码工程进行跟进。前端

基础知识

Servlet的基础知识

为何要先了解Servlet的知识呢,由于后面你会看到咱们所熟悉的SpringMVC其实也是一个Servlet,只是它封装了不少的东西并和Spring进行了整合,后面咱们进行的源码分析就是围绕着Servlet的生命周期进行的,因此有必要了解一下Servlet相关的知识。java

Servlet概念

全称Java Servlet,是用Java编写的服务器端程序。其主要功能在于 交互式地浏览和修改数据,生成动态Web内容。Servlet运行于支持 Java应用的服务器中。从原理上讲,Servlet能够响应任何类型的请求, 但绝大多数状况下Servlet只用来扩展基于HTTP协议的Web服务器。ios

Servlet的工做原理

下面经过一张时序图来理解Servlet的工做流程程序员

从上面的时序图总结以下:web

  1. 首先客户端请求接入
  2. Servlet容器,好比Tomcat处理请求
  3. Tomcat 建立HttpServletRequest对象,将请求的信息封装到这个对象中。
  4. Tomcat 建立HttpServletResponse对象, 此时是一个空的对象等待请求返回并填充
  5. Tomcat 调用service方法,最终传递到子类HttpServlet中
  6. HttpServlet从request中获取请求信息,处理完毕后将返回值信息封装到HttpServletResponse对象
  7. Tomcat容器返回处理后的信息
Servlet生命周期

打开Servlet源码发现Servlet接口有几个方法:spring

  1. init()方法Tomcat建立Servlet时会调用
  2. 每次有请求来时Tomcat都会调用service()方法
  3. 请求结束时Tomcat会调用destroy()方法
public interface Servlet {
   //Servlet建立时会调用init方法进行初始化
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();
	
   // 每次有新的请求来时都会调用
    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();
	
    // 请求结束时调用
    void destroy();
}
复制代码
一个Servlet例子

写一个AddUserServlet类继承自HttpServlet(为何要继承这个类后面有说明)数据库

public class AddUserServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/plain;charset=utf8");
		response.getWriter().write("添加成功");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}
复制代码

webapp/WEB-INF下新建web.xml后端

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
        <servlet>
    <description></description>
    <display-name>AddUserServlet</display-name>
    <servlet-name>AddUserServlet</servlet-name>
    <servlet-class>com.sjc.springmvc.servlet.AddUserServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>AddUserServlet</servlet-name>
    <url-pattern>/AddUserServlet</url-pattern>
  </servlet-mapping>
</web-app>
复制代码

将程序部署到Tomcat就能够访问了(具体不会的请读者查相关资料)

有同窗可能会产生疑惑:我都没有看到main方法,怎么就能够访问了呢?

回答以下:

Servlet其实是tomcat容器生成的,调用init方法能够初始化。他有别于 普通java的执行过程,普通java须要main方法;可是web项目因为是服务器控 制的建立和销毁,因此servlet的访问也须要tomcat来控制。经过tomcat访问 servlet的机制是经过使用http协议的URL来访问,因此servlet的配置完想要访 问,必须经过URL来访问,因此没有main方法。

应用系统三层架构

表现层

也就是咱们常说的web层

  1. 它负责接收客户端请求,向客户端响应结果,一般客户端使用http协议请求web层,web须要接收http请求,完成http响应
  2. 表现层包括展现层和控制层:控制层负责接收请求,展现层负责结果的展现
  3. 表现层依赖业务层,接收到客户端请求通常会调用业务层进行业务处理,并将处理结果响应给客户端
  4. 表现层的设计通常都使用MVC模型
业务层
  1. 也就是咱们常说的service层。
  2. 它负责业务逻辑处理,和咱们开发项目的需求息息相关。web层依赖业务层,可是业务层不依赖web层。
  3. 业务层在业务处理时可能会依赖持久层,若是要对数据持久化须要保证事务一致性。
持久层
  1. 也就是咱们常说的dao层。
  2. 负责数据持久化,包括数据层即数据库和数据库访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层须要经过数据访问层将数据持久化到数据库中
  3. 通俗的讲,持久层就是和数据库交互,对数据库表进行增删改的。

MVC设计模式

MVC是模型(model)、视图(view)、控制器(controller)的缩写,是一种用于设计编写web应用程序表现层的模式

MVC设计模式的三大角色:

  • Model(模型):

    模型包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。

  • View(视图): 一般指的是咱们的jsp或者html。做用通常就是展现数据的。

    一般视图是依据数据模型建立的。

  • Controller(控制器):

    是应用程序中处理用户交互的部分。做用通常就是处理程序逻辑的。

SpringMVC的流程分析

理解SpringMVC,只要你理解了下面介绍的六大组件基本上就能够了。后面的源码分析咱们也是围绕着这六大组件来的。

SpringMVC流程以下图所示:

总结以下:

  • DispatcherServlet: 前端控制器

    用户请求到达前端控制器,它就至关于MVC中的C,DispatcherServlet是整个流程控制的中心,由它调用其余组件处理用户的请求,DispatcherServlet的存在下降了组件之间的耦合性

  • Handler:处理器

    Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理

    因为Handler涉及到具体的用户业务请求,因此通常状况下须要程序员根据业务需求开发Handler

    经常使用的有好比Controller,HttpRequestHandler,Servlet、@RequestMapping等等,因此说处理器实际上是一个宽泛的概念

  • View:视图

    SpringMVC框架提供了不少的view视图类型的支持,包括:jstlview、freemarkerview、pdfview等。咱们最多见的视图就是jsp。固然,如今不多用jsp了,如今大部分都是先后端分离了,因此后面源码分析咱们会忽略视图

  • HandlerMapping: 处理器映射器

    HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不一样的映射器实现不一样的映射方式好比:配置文件方式(BeanNameUrlHandlerMapping)、实现接口方式和注解方式(RequestMappingHandlerMapping)等。

  • HandlerAdapter: 处理适配器

    SpringMVC经过适配器模式,将不关联的DispatcherServlet和Handler进行关联,经过适配器调用具体的Handler实现。

  • View Resolver:视图解析器

    View Resolver负责将处理结果生成view视图,View Resolver首先根据逻辑视图解析成物理视图名即具体的页面地址,再生成view视图对象,最后对view进行渲染,将处理结果经过页面展现给用户。

Spring源码解析

初始化init()

咱们上面说过,分析源码的时候从Servlet入手,咱们看它的初始化init()。首先看下类结构图,咱们发现DispatcherServlet这个核心组件就是一个Servlet,回到开头咱们说的SpringMVC其实也是一个Servlet,只是作的事情比较多而已。

咱们顺着这个类关系图,找到了FrameworkServlet#initServletBean

这里初始化了spring容器WebApplicationContext

@Override
	protected final void initServletBean() throws ServletException {
	   //...省略若干代码
    // 初始化web环境中的spring容器WebApplicationContext
    this.webApplicationContext = initWebApplicationContext();
    initFrameworkServlet();
		//...省略若干代码
	}
复制代码

咱们进入到:FrameworkServlet#initWebApplicationContext

咱们找到了两个分支

  • configureAndRefreshWebApplicationContext

    这个分支会去初始化Spring容器,又会回到咱们SpringIOC容器初始化的那十二步骤,相关的能够阅读我以前分析的深度解析SpringIOC

  • onRefresh

    会刷新容器的策略,咱们主要看这一分支

protected WebApplicationContext initWebApplicationContext() {
	//...省略若干代码
  // 初始化spring容器
	configureAndRefreshWebApplicationContext(cwac);
  // 刷新容器中的策略
	onRefresh(wac);
  //...省略若干代码
}
复制代码

咱们根据onRefresh,发现最终会进入到DispatcherServlet#onRefresh

protected void onRefresh(ApplicationContext context) {
		// 初始化策略容器
		initStrategies(context);
	}
复制代码

咱们进入到DispatcherServlet#initStrategies

这里会初始各类解析器,好比咱们比较关心的处理器映射器,处理器适配器,至于为啥要在这里作初始化呢?SpringMVC为了扩展性,使用策略模式,将这些映射器适配器交给了配置文件,这样若是要再新增一个处理器就不须要改代码了,符合“对修改关闭,对扩展开放”的设计原则,这里的初始化也是为了策略模式作准备这个也是咱们学习源码学习到的知识,之后能够运用到咱们实际的项目中。

好比下面的xml配置文件:

initStrategies就是从SpringIOC容器中获取到这些Bean,而后放入Map中来进行初始化的。

<beans>
	<!-- Handler处理器类的配置 -->
	<!-- 经过bean标签,创建beanname和bean的映射关系 -->
	<bean name="/queryUser2" class="com.sjc.springmvc.handler.QueryUserHandler"></bean>
	<bean name="/addUser2" class="com.sjc.springmvc.handler.AddUserHandler"></bean>
	<!-- HandlerMapping配置 -->
	<bean class="com.sjc.springmvc.handlermapping.BeanNameUrlHandlerMapping" init-method="init"></bean>
  
	<!-- HandlerAdapter配置 -->
	<bean class="com.sjc.springmvc.handleradapter.HttpRequestHandlerAdapter"></bean>
</beans>
复制代码

读者感兴趣的话能够当作为一个分支进行验证。

protected void initStrategies(ApplicationContext context) {
		// 初始化多部件解析器
		initMultipartResolver(context);
		// 初始化国际化解析器
		initLocaleResolver(context);
		// 初始化主题解析器
		initThemeResolver(context);
		// 初始化处理器映射器
		initHandlerMappings(context);
		// 初始化处理器适配器
		initHandlerAdapters(context);
		// 初始化异常解析器
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		// 初始会视图解析器
		initViewResolvers(context);
		initFlashMapManager(context);
	}
复制代码

RequestMappingHandlerMapping初始化

在介绍HandlerMapping找到Handler的过程前,咱们先来看看,RequestMappingHandlerMapping的初始化过程发生了什么。我这里先给个结论:

咱们最终的目的就是经过url找到Handler(HandlerMethod)

咱们进入到RequestMappingHandlerMapping,看到其中只有这样的方法:

@Override
	public void afterPropertiesSet() {
		this.config = new RequestMappingInfo.BuilderConfiguration();
		this.config.setUrlPathHelper(getUrlPathHelper());
		this.config.setPathMatcher(getPathMatcher());
		this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
		this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
		this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
		this.config.setContentNegotiationManager(getContentNegotiationManager());
		// 调用父类AbstractHandlerMethodMapping的afterPropertiesSet方法
		super.afterPropertiesSet();
	}
复制代码

咱们眼前一亮,它为咱们提供了研究RequestMappingHandlerMapping初始化的入口,为何这么说呢?咱们知道SpringIOC提供了两种初始化方式: 第一种、就是在配置文件中中指定init-method方法,这种在我前面分析SpringIOC的文章能够看到**深刻解析SpringIOC; **第二种、就是子类实现InitializingBean接口。这个接口有一个方法:

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}
复制代码

这样在初始化Bean的时候会调用afterPropertiesSet()方法。

这个流程咱们在SpringIOC源码哪里能够看见呢?

咱们进入AbstractAutowireCapableBeanFactory#invokeInitMethods

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {

		//判断该bean是否实现了实现了InitializingBean接口,若是实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			if (System.getSecurityManager() != null) {
				try {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						//直接调用afterPropertiesSet
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				//直接调用afterPropertiesSet
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			//判断是否指定了init-method方法,若是指定了init-method方法,则再调用制定的init-method
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				//进一步查看该方法的源码,能够发现init-method方法中指定的方法是经过反射实现
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}
复制代码

这两种方式哪种先调用呢?

看源码咱们发现实现了InitializingBean接口的类在Bean进行初始化的时候先被调用,而后调用init-method指定的方法;

哪种方式的效率高呢?

固然是实现了InitializingBean接口的类方式,由于调用init-method指定的方法是经过反射实现的;可是经过映射文件方式消除了对spring的依赖

好了别跑远了,咱们接着看RequestMappingHandlerMapping#afterPropertiesSet

里面会调用父类AbstractHandlerMethodMapping#afterPropertiesSet

public void afterPropertiesSet() {
		// 初始化处理器方法对象
		initHandlerMethods();
	}
复制代码

接着进入:AbstractHandlerMethodMapping#initHandlerMethods

protected void initHandlerMethods() {
		// 获取当前spring容器的全部bean的name,并遍历
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				// 处理候选的Bean
				processCandidateBean(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
复制代码

咱们关心的是processCandidateBean

进入:AbstractHandlerMethodMapping#processCandidateBean

这里面主要作三件事:

  1. 根据bean的名称,从当前spring容器中获取对应的Bean的Type
  2. 判断是不是Handler,也就是是否有@Controller或者@RequestMapping修饰类,若是有则是Handler对象
  3. 查找并封装HandlerMethod对象
protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
			// 根据bean的名称,从当前spring容器中获取对应的Bean的Type
			beanType = obtainApplicationContext().getType(beanName);
		}
		catch (Throwable ex) {
			// An unresolvable bean type, probably from a lazy bean - let's ignore it.
			if (logger.isTraceEnabled()) {
				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
			}
		}
		// 若是是Handler,则须要查找HandlerMethod(若是带有@Controller或者@RequestMapping则是Handler对象)
		if (beanType != null && isHandler(beanType)) {
			// 重要入口
			// 从Controller或者RequestMapping注解的Bean中,找到全部的HandlerMethod对象,并进行存储
			detectHandlerMethods(beanName);
		}
	}
复制代码

咱们进入AbstractHandlerMethodMapping#detectHandlerMethods

这个方法比较复杂,主要用的lambda表达式太多,主要作这几件事:

  1. 将类上的@RequestMapping信息和Method上的Method信息封装成RequestMappingInfo对象
  2. 将Method方法和RequestMappingInfo对象创建映射,存储Map集合中
  3. 遍历methods,注册url和RequestMappingInfo映射关系,注册RequestMappingInfo和HandlerMethod的映射关系
protected void detectHandlerMethods(Object handler) {
		// 获取处理器类型
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

		if (handlerType != null) {
			// 若是该类是经过cglib代理的代理类,则获取其父类类型,不然的话,直接返回该类
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			// 存储Method方法和RequestMapping注解信息的映射关系(重点)
			// 该映射关系会解析成咱们须要的其余两个映射关系
			// key是Controller类中的Method对象,value是RequestMappingInfo对象
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> { // 此处是设置回调函数
						try {
							// 获取bean上面和method上面的RequestMapping注解信息,封装到RequestMappingInfo对象中
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});
			if (logger.isTraceEnabled()) {
				logger.trace(formatMappings(userType, methods));
			}
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				// 注册HandlerMethod和RequestMappingInfo对象的关系
				// 注册请求URL和RequestMappingInfo对象的关系
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}
复制代码

RequestMappingHandlerMapping初始化分析到此结束,在深刻下去就会没完没了。

处理请求service()

一样顺着下面的流程图咱们找到实现Servlet#service()方法的类HttpServlet

咱们来到:HttpServlet#service:

能够看到这里面将ServletRequest转成HttpServletRequest, ServletResponse转成HttpServletResponse,这样就能够作更多的事情了。

@Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }
复制代码

进入到HttpServlet#service(request, response):

全部的Http请求都会通过这里,可是咱们找半天没发现service实现代码在哪里,咱们看到HttpServlet是一个抽象类,通常类被设计成抽象类有两个因素:

  • 类中有抽象方法,须要子类实现
  • 没有抽象方法,可是类不但愿被实例化

那这个HttpServlet为何要设计成抽象类呢?别急,咱们看下类的注释文档:

翻译起来大概的意思就是我这个类不知道你子类是什么处理请求的,我不会帮你处理的,我这里定义好了各类请求,请你务必实现其中的某一个,否则我就给你返回错误。咱们看到这里就是用了抽象模板方法的设计模式:父类把其余的逻辑处理完,把不肯定的业务逻辑抽象成一个抽象方法,交给子类去实现。

/** * * Provides an abstract class to be subclassed to create * an HTTP servlet suitable for a Web site. A subclass of * <code>HttpServlet</code> must override at least * one method, usually one of these: * * <ul> * <li> <code>doGet</code>, if the servlet supports HTTP GET requests * <li> <code>doPost</code>, for HTTP POST requests * <li> <code>doPut</code>, for HTTP PUT requests * <li> <code>doDelete</code>, for HTTP DELETE requests * <li> <code>init</code> and <code>destroy</code>, * to manage resources that are held for the life of the servlet * <li> <code>getServletInfo</code>, which the servlet uses to * provide information about itself * </ul> * / 复制代码
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
复制代码

咱们顺藤摸瓜,找到实现HttpServlet的子类,看看哪一个子类实现了service()方法,咱们最终看到了DispatcherServlet实现了这个service()方法。

这里咱们千呼万唤的doDispatch终于出来了,这个doDispatch作了它擅长的事情,就是请求的分发,咱们得慢慢品,细细品这个方法。

@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
			//...省略掉无数代码
      // 处理请求分发(作调度)
			doDispatch(request, response);
	}
复制代码

咱们进入到:DispatcherServlet#doDispatch

咱们再回顾一下SpringMVC的处理流程:

这个方法就是干这件事情的,一张图胜似千言万语。你品,你细品

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请求
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				// 经过处理器映射器HandlerMapping,获取handler处理器执行链,该执行链封装了处理器和对应该处理器的拦截器(可能有多个)
				// 须要注意的是@Controller注解的类,它不是咱们这里要查找的处理器,咱们要查找的处理器是@RequestMapping对应的方法,这个方法会封装到HandlerMethod类中
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 经过找到的handler处理器,去匹配合适的处理器适配器HandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				// 执行拦截器(interceptor)的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				// 经过处理器适配器,真正调用处理器方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 设置默认视图名称
				applyDefaultViewName(processedRequest, mv);
				// 执行拦截器(interceptor)的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			// 处理调度结果(也就是ModelAndView对象)
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			// 执行拦截器(interceptor)的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			// 执行拦截器(interceptor)的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}
复制代码

SpringMVC策略模式

经过HandlerMapping找到Handler的过程

咱们先来看下请求经过HandlerMapping找到Handler的过程:

咱们进入到DispatcherServlet#getHandler

不出咱们所料,这里就遍历了咱们初始化阶段存储的handlerMappings集合,返回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;
	}
复制代码

何为策略模式呢?咱们一块儿来看:

咱们假设有这样的需求:咱们出行方式有不少种,好比火车,飞机,自行车,咱们只须要输入咱们有的钱就能够智能地匹配出咱们的出行方式

咱们来创建这样的模型:

定义一个策略类:

// 策略类
public interface TravelStrategy {
	
	//出行方式
	void travelWay();
	
	boolean isDone(int type);
}
复制代码

定义飞机出行方式类:AirStrategy

public class AirStrategy implements TravelStrategy {

	@Override
	public void travelWay() {
		System.out.println("坐飞机");
	}
	
	@Override
	public boolean isDone(int type) {
		if (type <= 1000 && type >500) {
			return true;
		}
		return false;
	}

}
复制代码

定义自行车出行方式类: BicycleStrategy

public class BicycleStrategy implements TravelStrategy {

	@Override
	public void travelWay() {
		System.out.println("自行车");
	}

	@Override
	public boolean isDone(int type) {
		if (type <= 20) {
			return true;
		}
		return false;
	}

}
复制代码

定义火车出行方式类:TrainStrategy

public class TrainStrategy implements TravelStrategy {

	@Override
	public void travelWay() {
		System.out.println("坐火车");
	}

	@Override
	public boolean isDone(int type) {
		if (type >= 20 && type < 400) {
			return true;
		}
		return false;
	}

}
复制代码

定义一个策略模式环境类(Context)

public class PersonContext {

	// 策略类集合
	private List<TravelStrategy> strategylist;

	public PersonContext() {
		this.strategylist = new ArrayList<>();
		strategylist.add(new AirStrategy());
		strategylist.add(new TrainStrategy());
		strategylist.add(new BicycleStrategy());
	}


	public void travel(int type) {
		// 输入一个数,循环遍历每一个策略类,进行最优选择
		for (TravelStrategy travelStrategy : strategylist) {
			if (travelStrategy.isOK(type)) {
				travelStrategy.travelWay();
				break;
			}
		}
	}
}
复制代码

测试类:

public class StrategyTest {
	@Test
	public void test() {
		// 策略环境类
		PersonContext person = new PersonContext();

		// 坐飞机
		person.travel(1500);

		// 坐火车
		person.travel(100);

		// 自行车
		person.travel(1);
	}
}
复制代码

输出:

坐飞机
坐火车
自行车
复制代码

咱们再来看SpringMVC中的策略模式,首先环境类DispatcherServlet, 初始化各个策略模式的是DispatcherServlet#initStrategies, 遍历策略选择最合适的策略的是:

@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;
	}
复制代码

策略模式消除了不少的if....else...代码,经过配置文件方式定义各类策略,是一种可扩展的设计模式。

咱们进入到AbstractHandlerMapping#getHandler

主要作两件事:

  • 经过请求获取处处理器对象
  • 经过处理器对象建立处理器执行链
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// 调用具体的子类去获取不一样类型的处理器对象(好比获取到的@Controller和@RequestMapping注解的处理器是HandlerMethod对象)
		Object handler = getHandlerInternal(request);
		//...省略若干代码
		// 建立处理器执行链
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

		//...省略若干代码

		return executionChain;
	}
复制代码

咱们来到实现类AbstractHandlerMethodMapping#getHandlerInternal

咱们看到这里的handler是HandlerMethod,这个类封装了controller和Method,

@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		// 获取查找路径(部分URL)
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		request.setAttribute(LOOKUP_PATH, lookupPath);
		this.mappingRegistry.acquireReadLock();
		try {
			// 根据请求查找路径(部分URL),获取最合适的HandlerMethod对象
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			// 对HandlerMethod对象包含的的bean属性进行实例化,再返回HandlerMethod对象
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}
复制代码

咱们进入到AbstractHandlerMethodMapping#lookupHandlerMethod

这里主要作:

  1. 根据请求路径(URL)去上面咱们分析到的urlLookup集合中获取匹配到的RequestMappingInfo集合

  2. 将RequestMappingInfo对象和HandlerMethod对象进行匹配,将匹配到的信息封装到Match对象,再将Match对象放入matches集合进行返回。

    此时咱们的处理器HandlerMethod已经找到。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
		// 根据查找路径(URL)去urlLookup集合中获取匹配到的RequestMappingInfo集合
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
			// 将RequestMappingInfo对象和HandlerMethod对象进行匹配,将匹配到的信息封装到Match对象,再将Match对象放入matches集合
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		//...省略寻找最优匹配的过程代码
	}
复制代码

SpringMVC适配器模式

咱们再回到DispatcherServlet#doService 方法中

找到Handler后按照咱们上面的流程图,接下来就是要找到HandlerAdapter。

咱们看到:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	
    // 经过找到的handler处理器,去匹配合适的处理器适配器HandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

}
复制代码

咱们进入到:DispatcherServlet#getHandlerAdapter

这里无非就是根据咱们初始化过程当中,将配置文件中的HandlerAdapters集合进行遍历,找到合适的HandlerAdapter。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				// 经过适配器的适配功能,去适配处理器,若是适配成功,则直接将适配器返回
				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");
	}
复制代码

这里用到了适配器模式,咱们来看看HandlerAdapter类:

public interface HandlerAdapter {

  // 判断是否与当前的适配器支持,若是支持返回true,不支持返回false
	boolean supports(Object handler);

  // 调用handler中的请求处理方法
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	
	long getLastModified(HttpServletRequest request, Object handler);

}
复制代码

SpringMVC这里为啥须要适配器呢?咱们来分析一下,因为处理器handler有不少,好比Controller,HttpRequestHandler,Servlet等等,从HandlerMapping中获取到的Handler是一个Object对象,这样在DispatcherServlet#getHandlerAdapter方法中若是不用适配器模式就可能这样写:

private HandlerAdapter getHandlerAdapter(Object handler) {
		if (handler instanceof HttpRequestHandler) {
			return new HttpRequestHandlerAdapter();
		} else if(handler instanceof Controller) {
      return new Controller
    }
		// else if.....
		return null;
	}
复制代码

若是再新增一个handler就得改代码,不符合“对修改关闭,对扩展开放”的设计原则。

SpringMVC这里就给每一个handler对应一个相应的适配器,好比针对Controller实现的handler对应的是SimpleControllerHandlerAdapter适配器,由SimpleControllerHandlerAdapter适配器调用Controller处理器处理相关逻辑,每一个handler的处理逻辑不同,之后再新增一个handler的时候,只用新增相应的适配器就能够了,这完美的解决了这个问题。但愿读者能细品其中的设计思想。

咱们继续看DispatcherServlet中的其余方法:

找到HandlerAdapter后,主要作如下几件事:

  1. 执行拦截器(interceptor)的preHandle方法
  2. 经过处理器适配器,真正调用处理器方法
  3. 执行拦截器(interceptor)的postHandle方法
  4. 处理调度结果(也就是ModelAndView对象)
  5. 执行拦截器(interceptor)的afterCompletion方法

SpringMVC的拦截器功能源码就在此步骤完成,若是读者对此感兴趣能够以此为分支进行深刻研究,至此SpringMVC源码分析告一段落。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//...省略若干代码
  		// 经过找到的handler处理器,去匹配合适的处理器适配器HandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  		// 执行拦截器(interceptor)的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				// 经过处理器适配器,真正调用处理器方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				// 设置默认视图名称
				applyDefaultViewName(processedRequest, mv);
				// 执行拦截器(interceptor)的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
 	 // 处理调度结果(也就是ModelAndView对象)
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		
  	// 执行拦截器(interceptor)的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		

}
复制代码
相关文章
相关标签/搜索