一、Spring MVC中重要角色
1.DispatcherServlet:前端控制器,接受所有web.xml中配置的请求,处理整个请求流程
2.HandlerMapping:处理映射器,根据请求的URL,找到对应的Handler,包括定义的拦截器
3.HandlerAdapter:Handler处理器适配器,处理不同类型的请求,主要包括有HttpReqeustHandlerAdapter、SimpleServletHandlerAdapter和SimpleControllerHandlerAdapter,这三种都比较简单,都是通过方法直接调用;RequestMappingHandlerAdapter这个处理器就是我们常用的注解形式,使用RequestMapping注解时的处理器,这种类型就是使用反射的方式调用;
4.Controller:后端处理器,用来接受请求,处理后端业务逻辑
5.ViewResolver:视图解析器,把逻辑视图解析成真正的物理视图
6.View:视图,将数据展现给用户
二、大致流程
我们先来看图1.用户发起请求到前端控制器(DispatcherServlet)
2.前端控制器会找到处理映射器(HandlerMapping)根据请求的URL,找到相应的处理器执行链
3.前端控制器找到处理器执行链后,再找到处理器适配器,找到处理器
4.执行处理器
5.处理器会返回一个ModelAndView
6.前端控制器会请求视图解析器解析视图
7.视图渲染,返回到用户页面
三、Spring MVC初始化流程源码解析
之前的所有源码分析,把整个过程的代码都粘贴上来了,感觉效率不高,很多一些不重要的代码占了大量的篇幅,导致整篇看下来抓不住重点;这次源码只粘贴重要的代码,这样过程就会很清晰。
首先Spring MVC初始化,是从我们再web.xml中配置DispatcherServlet,开始;DispatcherServlet继承了FrameworkServlet,FrameworkServlet继承了HttpServletBean,所以最开始的初始化是从HttpServletBean中的init()方法开始的
public final void init() throws ServletException {
...
//我们主要看这个初始化的方法
initServletBean();
...
}
protected final void initServletBean() throws ServletException {
...
try {
//初始WebApplicationContext容器
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
...
}
protected WebApplicationContext initWebApplicationContext() {
//获取父容器,如果我们配置了Spring的配置文件,会在这一步获取到Spring的容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
...
if (wac == null) {
//创建容器,把父容器传进去
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
onRefresh(wac);
}
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
//获取到容器类型,我们是配置在web.xml中的,使用的是XmlWebApplicationContext容器类型
Class<?> contextClass = getContextClass();
...
//实例化容器
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
//设置父容器
wac.setParent(parent);
//获取到我们的mvc配置文件
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
//根据配置初始化容器
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
...
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
//主要是看这一步,这里注册了一个容器初始化后的监听器,这一步是mvc初始化的关键
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac)
//初始化Spring容器,这个我们再spring源码分析的时候,分析过spring的加载过程,这里就不进去看了
wac.refresh();
}
这里就是容器初始化,我们主要是看到ContextRefreshListener这个监听器的注册,接下来,我们看看ContextRefreshListener这个监听器做了什么
/**
*我们看到ContextRefreshListener这个监听器,监听了ContextRefreshedEvent这个事件
*也就是spring容器初始化完成的事件
**/
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//执行了FrameworkServlet的onApplicationEvent方法
FrameworkServlet.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
//执行初始化mvc容器的方法
onRefresh(event.getApplicationContext());
}
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
//初始化上传文件解析器
initMultipartResolver(context);
//初始化本地化解析器
initLocaleResolver(context);
//初始化主题解析器
initThemeResolver(context);
//初始化Handler映射器处理器组件
initHandlerMappings(context);
//初始化处理器适配器
initHandlerAdapters(context);
//初始化处理器异常解析器
initHandlerExceptionResolvers(context);
//初始化视图解析器
initRequestToViewNameTranslator(context);
//初始化视图组件
initViewResolvers(context);
//初始化分布管理者
initFlashMapManager(context);
}
到这一步整个spring mvc初始化就完成了
四、spring mvc请求流程
因为DispatcherServlet继承了FrameworkServlet,FrameworkServlet继承了HttpServletBean,HttpServletBean继承了HttpServlet,也就是请求进来时,会调用到doPost或者doGet方法去,FrameworkServlet覆盖了这几个方法,我们看下doGet方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//无论是doPost还是doGet都是调用processRequest方法
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
try {
//执行doService方法
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
//发布ServletRequestHandledEvent事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
//设置request属性,所以我们可以在controller中获取到下面四个属性
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
...
try {
//开始进入doDispatch,这个就是前段控制器最重要的方法了,所有流程都在这个方法中
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
//这个方法我们就不省略代码了,这样流程会清晰一点
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//handler执行链,这个里会封装所有拦截器的集合,还有执行的handler
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);
//从映射器中获取处理器执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//从处理器适配器中获取处理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//获取请求方式
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;
}
}
//执行拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//使用处理器执行相应的handle,也就是我们的业务代码
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//视图处理(页面渲染)
applyDefaultViewName(processedRequest, mv);
//执行拦截器postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
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()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
Spring MVC的处理流程就结束了,太细节的东西就不讲了,大家自己有时间可以阅读下源码,例如怎么获取处理器执行链的,怎么获取处理器的,还有各种处理器是怎么去处理不同方式的请求的,带着这些问题去阅读源码。