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