5.SpringMVC

Spring MVC

1.实现原理之DispatcherServlet初始化

(1)DispatcherServlet与ApplicationContext的关系

DispatcherServlet 需要 WebApplicationContext(继承自 ApplicationContext) 来构建。WebApplicationContext 可以链接到ServletContext 和 Servlet。因为绑定了 ServletContext,这样应用程序就可以在需要的时候使用 RequestContextUtils 的静态方法访问 WebApplicationContext。

public DispatcherServlet(WebApplicationContext webApplicationContext) {
    super(webApplicationContext);
    this.setDispatchOptionsRequest(true);
}

大多数应用程序只有一个WebApplicationContext,除此之外也可以一个Root WebApplicationContext 被多个WebApplicationContext实例访问,然后各自拥有自己的WebApplicationContext 配置。【换句话说,一个 Web 应用可以有多个 Servlet ,而它们的 ServletContext 则是共用的一个。这个是由 Servlet 容器(如 Tomcat、Jetty )来决定

Root WebApplicationContext 包含需要共享给多个 Servlet 实例的数据源和业务服务基础 Bean。这些 Bean 可以在多个 Servlet 实例特定的范围被继承或覆盖。

官网:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet-context-hierarchy

(2)初始化过程

https://www.pdai.tech/md/spring/spring-x-framework-springmvc-source-1.html#dispatcherservlet%E6%98%AF%E5%A6%82%E4%BD%95%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84

总结:初始化WebApplicationContext配置然后再初始化DispatcherServlet中的组件(Resolver,HandlerAdapt,HandlerMapping等)

2.实现原理之DispatcherServlet处理请求过程

(1)图解处理请求过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xYFnH36L-1686813243447)(C:\Users\10059\AppData\Roaming\Typora\typora-user-images\image-20220721173708617.png)]

(2)源码分析-核心方法:doDispatch(HttpServletRequest request, HttpServletResponse response)

public class DispatcherServlet extends FrameworkServlet {
    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 {
                  //1.判断是否是文件上传请求,如果是就把请求包装一下返回
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				//2.根据请求去HandlerMapping里面根据RequestCondition匹配找到对应的Handler(具体Controller),然后将Handler,HandlerIntercept用HandlerExecutionChain封装,返回HandlerExecutionChain
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				//3.从HandlerExecutionChain中拿出Handler,用这个Handler去获取HandlerAdapter(因为DispatcherServlet实现的是FrameworkServlet接口,而Handler实现的是xxx接口,二者接口不一样,所以需要适配)
				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 (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

                  //4.1 调用HandlerIntercept拦截器的preHandle做前置拦截,如果请求在此处被拦截不放行了,那么就会不会去执行HandlerIntercept拦截器的afterCompletion方法,后续代码也不再执行。如果返回true,之后渲染视图后会去执行HandlerIntercept拦截器的afterCompletion方法,后续代码也会继续执行
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				//4.2 执行Handler内部的代码逻辑,返回ModelAndView数据
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
                  //4.3 调用HandlerIntercept拦截器的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);
			}
             //5.1拿到ModelAndView做视图解析,解析出View。然后拿Model数据做视图渲染,执行HandlerIntercept拦截器的afterCompletion方法,最后返回
			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);
				}
			}
		}
    }
}

总结:

  1. 判断当前请求是否是文件上传请求,如果是的话把请求包装一层返回
  2. 从HandlerMapping映射器内的HandlerMap中找是否有符合的Handler(包含HandlerMethod,保存的是方法和url的映射关系),如果找到了就将具体Handler,HandlerIntercept封装成一个HandlerExecutionChain返回。如果找不到则抛出异常
  3. 从HandlerExecution中拿出Handler,获取到这个Handler的HandlerAdapt适配器(因为DispatcherServlet和Handler实现的接口不同,需要利用适配器模式)
  4. 调用HandlerIntercept拦截器的preHandler做前置拦截,如果请求在此处被拦截(返回false),则不再继续向下执行。如果返回true,放行
  5. 执行Handler的业务逻辑方法,返回ModelAndView。如果中途发生异常则退出程序
  6. 调用HandlerIntercept拦截器的postHandler做后置拦截
    ,如果请求在此处被拦截(返回false),则不再继续向下执行。如果返回true,放行
  7. 执行Handler的业务逻辑方法,返回ModelAndView。如果中途发生异常则退出程序
  8. 调用HandlerIntercept拦截器的postHandler做后置拦截
  9. 拿到ModelAndView做视图的解析和渲染工作,正常执行过后执行HandlerIntercept拦截器的afterCompletion方法(只要preHandle返回true就会执行afterCompletion)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值