一、概述
学习之后,记下笔记,理清思路。
带着问题去思考:
springMVC接收到用户请求之后,如何工作?
springMVC核心组件有哪些?
哪些是程序员需要编写的部分?
二、SpringMVC工作流程
工作流程:
- 用户发送请求;
- DispatcherSerlvet(前端控制器) 接收请求,调用HandlerMapping;
- HandlerMapping(处理器映射器) 去查找处理器Handler(就是Controller),HandlerMapping 返回执行链HandlerExecutionChain(包括Handler对象、拦截器数组)给DispatcherSerlvet;
- DispatcherSerlvet调用HandlerAdapter(处理器适配器);
- HandlerAdapter去执行Handler;
- Handler返回ModelAndView给HandlerAdapter;
- HandlerAdapter返回ModelAndView给DispatcherSerlvet;
- DispatcherSerlvet调用ViewResolver(视图解析器)进行视图解析;
- ViewResolver返回视图对象;
- DispatcherSerlvet进行视图渲染
- 返回渲染后对象;
- 响应请求。
三、核心组件
前端控制器DispatcherSerlvet
控制中心,接收请求,转发请求,响应请求
处理器映射器 HandlerMapping
查找处理器Handler
处理器适配器 HandlerAdapter
执行处理器Handler
视图解析器 ViewResolver
解析ModelAndView
处理器Handler (需要工程师开发)
Controller
视图View (需要工程师开发jsp...)
前端页面
四、源码分析
1、IDEA创建SpringMVC项目
参考:
创建出现的问题:
1 | web.xml中出现“element servlet-name is not allow here”, 导致系统启动失败 |
|
2 | 报错:org.apache.catalina.core.StandardContext.listenerStart Error configuring application listener of class org.springframework.web.context.ContextLoaderListener | 参考: |
创建一个简单的SpringMVC项目,只关注SpringMVC的工作流程。
2、简单写个接口
@Controller
@RequestMapping("/mvc")
public class HelloWorldController {
@RequestMapping("helloWorld")
public String hello(){
return "helloWorld";
}
}
3、分析DispatcherServlet
思路:DispatcherServlet继承FrameworkServlet,就是servlet,
servlet分:初始化,处理方法,销毁方法
核心就是service,
(下图是FrameworkServlet中的service方法)
再看关键的processRequest方法
点进去一看,是个抽象方法
那DispatcherServlet肯定重写了该方法
//DispatcherServlet.java
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if(this.logger.isDebugEnabled()) {
String attributesSnapshot = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?" resumed":"";
this.logger.debug("DispatcherServlet with name \'" + this.getServletName() + "\'" + attributesSnapshot + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
HashMap attributesSnapshot1 = null;
if(WebUtils.isIncludeRequest(request)) {
attributesSnapshot1 = new HashMap();
Enumeration inputFlashMap = request.getAttributeNames();
label108:
while(true) {
String attrName;
do {
if(!inputFlashMap.hasMoreElements()) {
break label108;
}
attrName = (String)inputFlashMap.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot1.put(attrName, request.getAttribute(attrName));
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
FlashMap inputFlashMap1 = this.flashMapManager.retrieveAndUpdate(request, response);
if(inputFlashMap1 != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap1));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
this.doDispatch(request, response); //关键方法
} finally {
if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot1);
}
}
}
再看doDispatch,做了啥,看见了关键词getHandler、getHandlerAdapter
getHandler,返回 HandlerExecutionChain
getHandlerAdapter,返回 HandlerAdapter
4、调用getHandler,获取HandlerExecutionChain
在上面的两个方法上打断点,
this.handlerMappings 有三个元素
this.handlerMappings有三种类型,根据request请求使用不同的HandlerMapping
RequestMappingHandlerMapping
(支持带@RequestMapping
注释的方法)- BeanNameUrlHandlerMapping
SimpleUrlHandlerMapping
(维护URI路径模式到处理程序的显式注册)。
返回handler(一个HandlerExecutionChain对象,包含了处理器controller和一个或多个拦截器),对应DispatcherServlet中的mappedHandler
4、调用getHandlerAdapter,获取HandlerAdapter
this.handlerAdapters有三种
- HttpRequestHandlerAdapter
- SimpleControllerHandlerAdapter
- RequestMappingHandlerAdapter
遍历所有类型,判断是否支持当前处理器handler
匹配RequestMappingHandlerAdapter,返回
进行到这一步,真正执行我们编写的处理器(Controller)
返回ModelAndView
后面还有视图解析。