SpringMVC工作原理及源码解析
- 一:SpringMVC原理图
- 二:SpringMVC的主要组件
- 1、前端控制器DispatcherServlet:
- 2、处理器映射器HandlerMapping:
- 3、处理器适配器HandlerAdapter:
- 4、处理器Handler:
- 5、控制器Controller:
- 6、视图解析器ViewResolver:
- 7、视图View
- 三:Spring MVC的工作流程
- 四:Spring 如何保证 Controller 并发的安全?
- 1、SpringMVC一个Controller处理所有用户请求的并发问题
- 2、Spring并发访问的线程安全性问题
一:SpringMVC原理图
二:SpringMVC的主要组件
1、前端控制器DispatcherServlet:
Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
我们知道Servlet的service方法是被Servlet容器调用的,这个时机是发生的有客户端向servlet请求服务时调用的,而这些都将其委托给DispatcherServlet的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 {//检查请求是否是multipart(即文件上传),若是进行相关处理processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);//通过handermapping映射获取HandlerExecutionChain(处理链中包括了interceptor的前置和后置方法)// Determine handler for the current request.mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}//根据处理器(handler及HandlerExecutionChain)获取处理器适配器(处理器适配器是为了提供统一接口进行后续处理,从而支持多种类型的处理器)// 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;}}//执行chain中拦截器附加的预处理方法,即preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}//适配器统一执行handle方法(适配器统一接口的作用),此处是真正处理业务逻辑的地方// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);//执行chain中拦截器附加的后处理方法,即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);}//处理分发结果:包括解析视图并进行视图渲染,执行chain中拦截器附加的后处理方法,即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 afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}
2、处理器映射器HandlerMapping:
能够完成客户请求到Controller映射。
3、处理器适配器HandlerAdapter:
经过适配调用具体的处理器(Handler,也叫后端控制器),即相应的Controller
将Controller执行结果ModelAndView返回给 DispatcherServlet
4、处理器Handler:
一般来说,Controller是Handler,但Handler不一定是Controller。
例如,HttpRequestHandler,WebRequestHandler,MessageHandler都是可以使用DispatcherServlet的处理程序。 @Controller是执行Web请求并返回视图的处理程序。
简而言之,Handler只是一个术语,它不是一个类或接口。 它可以执行映射。
执行流程都是:
处理映射器通过@Controller注解找到处理器,继而通过@RequestMapping注解找到用户输入的url
5、控制器Controller:
需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个
Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
6、视图解析器ViewResolver:
Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。
7、视图View
View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等 等)
三:Spring MVC的工作流程
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器, 请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦 截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给 DispatcherServlet; (8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行 解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
- 截获符合特定格式的URL请求。
- 初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的 WebApplicationContext建立关联。
- 初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。
四:Spring 如何保证 Controller 并发的安全?
1、SpringMVC一个Controller处理所有用户请求的并发问题
有状态和无状态的对象基本概念:
有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。一般是prototype scope。
无状态对象(Stateless Bean),就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。一般是singleton scope。
springMVC中,一般Controller、service、DAO层的scope均是singleton;
每个请求都是单独的线程,即使同时访问同一个Controller对象,因为并没有修改Controller对象,相当于针对Controller对象而言,只是读操作,没有写操作,不需要做同步处理。
Service层、Dao层用默认singleton就行,虽然Service类也有dao这样的属性,但dao这些类都是没有状态信息的,也就是 相当于不变(immutable)类,所以不影响。
2、Spring并发访问的线程安全性问题
由于Spring MVC默认是Singleton的,所以会产生一个潜在的安全隐患。根本核心是instance变量保持状态的问题。这意味着每个request过来,系统都会用原有的instance去处理,这样导致了两个结果:
一是我们不用每次创建Controller,
二是减少了对象创建和垃圾收集的时间;
由于只有一个Controller的instance,当多个线程同时调用它的时候,它里面的instance变量就不是线程安全的了,会发生窜数据的问题。当然大多数情况下,我们根本不需要考虑线程安全的问题,比如dao,service等,除非在bean中声明了实例变量。因此,我们在使用spring mvc 的contrller时,应避免在controller中定义实例变量。