文章目录
- 概要
- 启动阶段
- 请求阶段
概要
以下是调试mvc源码过程中用到的demo以及配置文件
webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath*:springmvc.xml</param-value></init-param><!-- load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法) --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd
"><!--开启controller扫描--><context:component-scan base-package="com.ocean.base.controller"/><!--配置springmvc的视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean><!--自动注册最合适的处理器映射器,处理器适配器(调用handler方法)--><!--<mvc:annotation-driven/>--></beans>
Controller
@Controller
@RequestMapping("/demo")
public class DemoController {@RequestMapping("/handle01")public String handle01(String name, Map<String, Object> model) {System.out.println("++++++++handler业务逻辑处理中....");Date date = new Date();model.put("date", date);return "success";}@RequestMapping("/index")public ModelAndView getModeAndView() {//创建一个模型视图对象ModelAndView mav = new ModelAndView("index");return mav;}
}
mvc调用的主流程
DispatcherServlet
(前端控制器) 是个servlet
,负责接收Request
并将Request
转发给对应的处理组件。HanlerMapping
(处理器映射器)是SpringMVC 中完成url 到Controller
映射的组件。DispatcherServlet
从HandlerMapping
查找处理Request
的Controller
,HanlerMapping
返回一个执行器链(url 到Controller 映射的组件)给DispatcherServlet
DispatcherServlet
请求处理器适配器HandlerAdapter
- 处理器适配器
HandlerAdapter
去访问我们的handler(controller)
handler(controller)
返回ModelAndView
给处理器适配器HandlerAdapter
- 处理器适配器
HandlerAdapter
返回ModelAndView
给DispatcherServlet
DispatcherServlet
请求ViewResolver
视图解析器ViewResolver
视图解析器返回view给DispatcherServlet
DispatcherServlet
请求view做页面解析和渲染view
将渲染好的数据返回给DispatcherServlet
,DispatcherServlet
将渲染好的字符流给client,看到了页面!
启动阶段
先来看总体的类关系图
项目启动后,会先执行javax.servlet.Servlet#init
方法,从而进行初始化,而·org.springframework.web.servlet.HttpServletBean#init
实现了该接口,进而在这个实现方法里面有调到了org.springframework.web.servlet.FrameworkServlet#initServletBean
,整个web容器便是在该方法中初始化完成
在web容器创建后,会调用到ioc容器的初始化方法
在ioc容器初始阶段的最后,会发布一个事件
在org.springframework.web.servlet.FrameworkServlet.ContextRefreshListener
会监听到该事件
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {FrameworkServlet.this.onApplicationEvent(event);
}public void onApplicationEvent(ContextRefreshedEvent event) {this.refreshEventReceived = true;synchronized (this.onRefreshMonitor) {onRefresh(event.getApplicationContext());}
}
监听到事件后,就开始初始化mvc的9大组件
protected void initStrategies(ApplicationContext context) {// 多文件上传initMultipartResolver(context);// 初始化本地语言环境initLocaleResolver(context);// 初始化模板处理器initThemeResolver(context);// 初始化HandlerMappinginitHandlerMappings(context);// 初始化HandlerAdapterinitHandlerAdapters(context);// 初始化异常处理拦截器initHandlerExceptionResolvers(context);// 初始化视图预处理器initRequestToViewNameTranslator(context);// 初始化视图转换器initViewResolvers(context);// 初始化FlashMap管理器initFlashMapManager(context);}
请求阶段
项目启动后,在浏览器中访问:http://localhost:8080/springmvc/index
是,首先会经过`javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse),在该方法中会调用。
javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
,该方法被子类org.springframework.web.servlet.FrameworkServlet#service
所覆盖,这时会跑到子类中进行执行
@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());if (httpMethod == HttpMethod.PATCH || httpMethod == null) {processRequest(request, response);}else {// 子类中又调了父类的另外一个service方法super.service(request, response);}}protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < lastModified) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp);} else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}
org.springframework.web.servlet.FrameworkServlet#doGet
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContext localeContext = buildLocaleContext(request);RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());initContextHolders(request, localeContext, requestAttributes);try {//重点查看,跳到DispatcherServlet 类中(子类重写)doService(request, response);}
...
}
org.springframework.web.servlet.DispatcherServlet#doService
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {logRequest(request);....RequestPath requestPath = null;if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {requestPath = ServletRequestPathUtils.parseAndCache(request);}try {//重点关注doDispatch(request, response);} finally {...}
}
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);// 根据当前的请求去拿一个Handler.这里包括拦截器mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// 处理器适配器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;}}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) {// 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 afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
}
以上就是大体的执行请求流程