一愿阐、Spring MVC中重要角色
1.DispatcherServlet:前端控制器垃喊,接受所有web.xml中配置的請(qǐng)求绎速,處理整個(gè)請(qǐng)求流程
2.HandlerMapping:處理映射器鉴裹,根據(jù)請(qǐng)求的URL赎线,找到對(duì)應(yīng)的Handler廷没,包括定義的攔截器
3.HandlerAdapter:Handler處理器適配器,處理不同類型的請(qǐng)求垂寥,主要包括有HttpReqeustHandlerAdapter颠黎、SimpleServletHandlerAdapter和SimpleControllerHandlerAdapter,這三種都比較簡(jiǎn)單滞项,都是通過(guò)方法直接調(diào)用狭归;RequestMappingHandlerAdapter這個(gè)處理器就是我們常用的注解形式,使用RequestMapping注解時(shí)的處理器文判,這種類型就是使用反射的方式調(diào)用过椎;
4.Controller:后端處理器,用來(lái)接受請(qǐng)求戏仓,處理后端業(yè)務(wù)邏輯
5.ViewResolver:視圖解析器疚宇,把邏輯視圖解析成真正的物理視圖
6.View:視圖,將數(shù)據(jù)展現(xiàn)給用戶
二赏殃、大致流程
我們先來(lái)看圖1.用戶發(fā)起請(qǐng)求到前端控制器(DispatcherServlet)
2.前端控制器會(huì)找到處理映射器(HandlerMapping)根據(jù)請(qǐng)求的URL敷待,找到相應(yīng)的處理器執(zhí)行鏈
3.前端控制器找到處理器執(zhí)行鏈后,再找到處理器適配器仁热,找到處理器
4.執(zhí)行處理器
5.處理器會(huì)返回一個(gè)ModelAndView
6.前端控制器會(huì)請(qǐng)求視圖解析器解析視圖
7.視圖渲染榜揖,返回到用戶頁(yè)面
三、Spring MVC初始化流程源碼解析
之前的所有源碼分析,把整個(gè)過(guò)程的代碼都粘貼上來(lái)了举哟,感覺(jué)效率不高思劳,很多一些不重要的代碼占了大量的篇幅,導(dǎo)致整篇看下來(lái)抓不住重點(diǎn)妨猩;這次源碼只粘貼重要的代碼潜叛,這樣過(guò)程就會(huì)很清晰。
首先Spring MVC初始化册赛,是從我們?cè)賥eb.xml中配置DispatcherServlet钠导,開(kāi)始;DispatcherServlet繼承了FrameworkServlet森瘪,F(xiàn)rameworkServlet繼承了HttpServletBean,所以最開(kāi)始的初始化是從HttpServletBean中的init()方法開(kāi)始的
public final void init() throws ServletException {
...
//我們主要看這個(gè)初始化的方法
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的配置文件扼睬,會(huì)在這一步獲取到Spring的容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
...
if (wac == null) {
//創(chuàng)建容器,把父容器傳進(jìn)去
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();
...
//實(shí)例化容器
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
//設(shè)置父容器
wac.setParent(parent);
//獲取到我們的mvc配置文件
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
//根據(jù)配置初始化容器
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
...
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
//主要是看這一步,這里注冊(cè)了一個(gè)容器初始化后的監(jiān)聽(tīng)器特纤,這一步是mvc初始化的關(guān)鍵
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容器军俊,這個(gè)我們?cè)賡pring源碼分析的時(shí)候,分析過(guò)spring的加載過(guò)程捧存,這里就不進(jìn)去看了
wac.refresh();
}
這里就是容器初始化粪躬,我們主要是看到ContextRefreshListener這個(gè)監(jiān)聽(tīng)器的注冊(cè),接下來(lái)昔穴,我們看看ContextRefreshListener這個(gè)監(jiān)聽(tīng)器做了什么
/**
*我們看到ContextRefreshListener這個(gè)監(jiān)聽(tīng)器镰官,監(jiān)聽(tīng)了ContextRefreshedEvent這個(gè)事件
*也就是spring容器初始化完成的事件
**/
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//執(zhí)行了FrameworkServlet的onApplicationEvent方法
FrameworkServlet.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
//執(zhí)行初始化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);
}
到這一步整個(gè)spring mvc初始化就完成了
四、spring mvc請(qǐng)求流程
因?yàn)镈ispatcherServlet繼承了FrameworkServlet吗货,F(xiàn)rameworkServlet繼承了HttpServletBean泳唠,HttpServletBean繼承了HttpServlet,也就是請(qǐng)求進(jìn)來(lái)時(shí)宙搬,會(huì)調(diào)用到doPost或者doGet方法去笨腥,F(xiàn)rameworkServlet覆蓋了這幾個(gè)方法,我們看下doGet方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//無(wú)論是doPost還是doGet都是調(diào)用processRequest方法
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
try {
//執(zhí)行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");
}
}
}
//發(fā)布ServletRequestHandledEvent事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
//設(shè)置request屬性勇垛,所以我們可以在controller中獲取到下面四個(gè)屬性
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 {
//開(kāi)始進(jìn)入doDispatch脖母,這個(gè)就是前段控制器最重要的方法了,所有流程都在這個(gè)方法中
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);
}
}
}
}
//這個(gè)方法我們就不省略代碼了窥摄,這樣流程會(huì)清晰一點(diǎn)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//handler執(zhí)行鏈镶奉,這個(gè)里會(huì)封裝所有攔截器的集合,還有執(zhí)行的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);
//從映射器中獲取處理器執(zhí)行鏈
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//從處理器適配器中獲取處理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//獲取請(qǐng)求方式
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;
}
}
//執(zhí)行攔截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//使用處理器執(zhí)行相應(yīng)的handle,也就是我們的業(yè)務(wù)代碼
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//視圖處理(頁(yè)面渲染)
applyDefaultViewName(processedRequest, mv);
//執(zhí)行攔截器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的處理流程就結(jié)束了哨苛,太細(xì)節(jié)的東西就不講了鸽凶,大家自己有時(shí)間可以閱讀下源碼,例如怎么獲取處理器執(zhí)行鏈的建峭,怎么獲取處理器的玻侥,還有各種處理器是怎么去處理不同方式的請(qǐng)求的,帶著這些問(wèn)題去閱讀源碼亿蒸。