Spring MVC的原理

Spring MVC中的MVC即模型-视图-控制器,该框架围绕一个DispatcherServlet设计而成,DispatcherServlet会把请求分发给各个处理器,并支持可配置的处理器映射和视图渲染等功能。Spring MVC的具体工作流程如下:
(1)客户端发起HTTP请求:客户端将请求提交到DispatcherServlet
(2)寻找处理器:由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理该请求的Controller
(3)调用处理器:DispatcherServlet将请求提交到Controller
(4)调用业务处理逻辑并返回结果;Controller在调用业务处理逻辑后,返回ModelAndView
(5)处理视图映射并返回模型:DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
(6)HTTP响应:视图负责将结果在客户端浏览器上渲染和展示。
在这里插入图片描述核心代码doDispatch

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

            // Determine handler for the current request.
            /*
            	mappedHandler:调用链
                包含handler、interceptorList、interceptorIndex
            	handler:浏览器发送的请求所匹配的控制器方法
            	interceptorList:处理控制器方法的所有拦截器集合
            	interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行
            */
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
           	// 通过控制器方法创建相应的处理器适配器,调用所对应的控制器方法
            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;
                }
            }
			
            // 调用拦截器的preHandle()
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // 由处理器适配器调用具体的控制器方法,最终获得ModelAndView对象
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            // 调用拦截器的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);
        }
        // 后续处理:处理模型数据和渲染视图
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        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);
            }
        }
    }
}

HandlerMapping介绍

HandlerMapping在这个SpringMVC体系结构中有着举足轻重的地位,充当着url和Controller之间映射关系配置的角色。HandlerMapping是接口,Spring MVC提供了一系列HandlerMapping的实现,根据一定的规则选择controller。如果当前的HandlerMappign实现中没有能够满足你所需要的规则是,可以通过实现HandlerMapping接口进行扩展。它主要有三部分组成:HandlerMapping映射注册、根据url获取对应的处理器、拦截器注册。
总结
HandlerMapping是处理器映射器,根据请求找到处理器Handler,但并不是简单的返回处理器,而是将处理器和拦截器封装,形成一个处理器执行链(HandlerExecuteChain)。
核心伪代码如下:
getHandler伪代码

 1 // 获取处理器执行链对象
 2 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 3    // SpringMVC默认实现三种类型的HandlerMapping: 
 4    // RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
 5    if (this.handlerMappings != null) {
 6       // 遍历MVC容器中的处理器映射器
 7       for (HandlerMapping mapping : this.handlerMappings) {
 8          // 获取请求对应的处理器执行链
 9          HandlerExecutionChain handler = mapping.getHandler(request);
10          // 处理器执行链不为空
11          if (handler != null) { 
12             // 返回匹配到的处理器执行链 
13             return handler;  
14          }
15       }
16    }
17    // 返回null
18    return null;  
19 }

getHandler获取执行器链

1 // 为请求获取handler处理器,若没有Handler处理器,获取mvc默认的handler处理器
 2 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 3    // 获得处理器(HandlerMethod或者HandlerExecutionChain),该方法是抽象方法,由子类实现
 4    Object handler = getHandlerInternal(request);
 5    // 获得不到,则使用默认处理器
 6    if (handler == null) {
 7       handler = getDefaultHandler();
 8    }
 9    // 获得不到,则返回 null
10    if (handler == null) {
11       return null;
12    }
13    
14    // 如果找到的处理器是String类型,则从Spring容器中找到对应的Bean作为处理器
15    if (handler instanceof String) {
16       String handlerName = (String) handler;
17       handler = obtainApplicationContext().getBean(handlerName);
18    }
19 
20    // 创建HandlerExecutionChain对象(包含处理器和拦截器)
21    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
22 
23    // 跨域请求的处理
24    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
25       CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
26       CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
27       config = (config != null ? config.combine(handlerConfig) : handlerConfig);
28       executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
29    }
30 
31    return executionChain;
32 }

getHandlerExectuionChain 构建执行器链

 1 //  为handler处理器构建HandlerExecutionChain对象,包含应用拦截器
 2 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
 3    // 创建 HandlerExecutionChain 对象
 4    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
 5          (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
 6 
 7    // 获得请求路径
 8    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
 9    // 遍历 adaptedInterceptors 数组,获得请求匹配的拦截器
10    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
11       // 需要匹配,若路径匹配,则添加到 chain 中
12       if (interceptor instanceof MappedInterceptor) {
13          MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
14          if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
15             chain.addInterceptor(mappedInterceptor.getInterceptor());
16          }
17       }
18       // 无需匹配,直接添加到 chain 中
19       else {
20          chain.addInterceptor(interceptor);
21       }
22    }
23    return chain;
24 }

相关问题

1.为什么不直接调用对应handler处理请求,而是先找到适配器
提到适配器,就知道它应用了适配器模式。
为什么要用适配器模式呢?
因为控制器接受请求的方式不同,即实现Controller的方式不同。有三种实现方式,一种是实现Controller接口方式,一种是用@Controller注解的方式,还有一种是直接接受的Http请求。
不同的Controller的实现方式,如果用if…else判断去处理的话,就会违背开放封闭原则 。

if(controller typeof  @Controller){
	处理@Controller注解逻辑
}
if(controller typeof ControllerInterface){
	处理实现controller接口的逻辑
}
if(controller typeof http){
	处理实现http请求类型的逻辑
}

因为多加一种controller实现方式就得多一个判断。因此SpringMVC就引入了适配器模式
而HandlerAdapter组件具有接口转换的能力,可以统一使用该接口来处理不同的controller的实现。
方便controller的扩展。
这里就是把变化的controller上面建立一层统一处理层,封装、屏蔽底层的controller实现方式的变化。
在这里插入图片描述

2.HandlerExecutionChain使用了什么设计模式,结合源码分析
责任链模式属于三种设计模式分类中行为型模式,责任链模式为请求对象创建一个接收者处理链,通常接收者中会存在下一个接收者的引用,如果当前接收者无法处理当前请求时,则将请求对象传递到下一个接收者进行处理,从而实现责任链,直到可以处理请求对象为止。责任链模式中请求发送者无需知道是哪个接收者处理的请求对象以及请求对象处理的具体过程,能够很好的将请求发送者和接收者进行解耦。责任链模式通常用于各种过滤器链、拦截处理链中,例如JavaWeb中的Filter过滤器等等。Spring框架中责任链模式的应用有很多,包括web请求设计,security安全权限设计,aop切面设计等等。

SpringMVC中实际上是基于Servlet的框架,当客户端发送请求到web时,都会进入DispatcherServlet中,然后根据Servlet的生命周期去执行doService方法,在doService方法中有一个关键方法doDispatch,其中就运用到得了责任链模式来对进来的请求进行处理。

	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 {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
				//获取处理对象
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				//责任链模式实现一:执行调用链的前置处理
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				//处理请求
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				applyDefaultViewName(processedRequest, mv);
				//责任链模式实现二:执行调用链的后置处理
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

HandlerExecutionChain的责任链模式,将需要执行的HandlerInterceptor拦截器,添加在HandlerExecutionChain责任链的interceptorList集合中,然后依次执行HandlerInterceptor相应的处理方法。以preHandle方法为例,在处理方法中,根据返回的处理boolean判断是否要继续进行下面的HandlerInterceptor对象的处理,最终完成整个调用链的拦截处理。HandlerExecutionChain的实现实际上是责任链模式的一种变性用法,它减少了不同处理对象的引用依赖,采用集合的方式来存放处理链对象,降低了耦合度

	//HandlerExecutionChain的applyPreHandle方法
	//责任链模式,将处理对象给接收者,并不关心内部如何处理与调用
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
			for (int i = 0; i < this.interceptorList.size(); i++) {
				HandlerInterceptor interceptor = this.interceptorList.get(i);
				//调用拦截器的preHandle方法,执行所有拦截器的preHandle处理方法
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
			return true;
	}
 

参考:http://www.manongjc.com/detail/41-uiajoseglafvxgf.html
https://blog.csdn.net/shang_0122/article/details/119335479
转载:https://blog.csdn.net/weixin_41605937/article/details/133376446

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值