2023-03-09
配置 contextconfiglocation 方法 dispatcherservlet 文件
2 前端控制器DispatcherServlet
2.1 DispatcherServlet源碼分析
1.繼承關系分析:DispatcherServlet類-FrameworkServlet類-HttpServletBean類-HttpServlet類-GenericServlet類。
2.先找到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 {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 確定當前請求的處理程序。獲取Handler執行鏈。
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(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;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
3.處理器執行鏈HandlerExecutionChain處理request請求。繼續跟蹤HandlerMapping的getHandler方法。
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// handlerMappings是Servlet所支持的處理器映射器的集合,這里有N個處理器映射器
for (HandlerMapping mapping : this.handlerMappings) {
// 獲取處理器執行鏈
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
4.繼續跟進HandlerExecutionChain getHandler(HttpServletRequest request)方法,此方法來自AbstractHandlerMapping類。
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// Ensure presence of cached lookupPath for interceptors and others
if (!ServletRequestPathUtils.hasCachedPath(request)) {
initLookupPath(request);
}
// 將請求request對象和處理器handler對象封裝成一個處理器執行鏈
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
5.繼續跟進getHandlerExecutionChain(Object handler, HttpServletRequest request)方法。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 獲取處理器執行鏈對象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
// 這里可以看出具有多個攔截器,而且攔截器是根據請求路徑做匹配的
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
// 處理器執行鏈chain對象中最終封裝的信息為:interceptor攔截器和handler處理器
return chain;
}
2.2 contextConfigLocation參數
1.屬性contextConfigLocation:表示用于加載Bean的配置文件。
2.如果沒有顯示的配置contextConfigLocation參數,SpringMVC默認會去“/WEB-INF/[servlet名字]-servlet.xml”讀配置文件。默認配置文件設置可通過org.springframework.web.context.support.XmlWebApplicationContext類中的源碼來確定。、
// 根上下文的默認位置是“/WEB-INF/applicationContext.xml”,對于命名空間為“test-servlet”的上下文,則是“/WEB-INF/test-servlet.xml”(類似于servlet名稱為“test”的DispatcherServlet實例)。
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
說明:如果想查看XmlWebApplicationContext類的源碼,可以通過Idea窗口的【Navigate】-【Search Everywhere】選項,在打開的窗口中搜索對應的類名稱即可找到類的所在位置。
3.DispatcherServlet配置初始化參數contextConfigLocation方式見下。
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
</servlet>
4.contextConfigLocation參數可以省略不寫,但是必須保證Bean的配置文件按照“/WEB-INF/[servlet名字]-servlet.xml”規則進行定義;否則項目啟動時將找不到Bean配置文件,會報FileNotFoundException的異常。
開班時間:2021-04-12(深圳)
開班盛況開班時間:2021-05-17(北京)
開班盛況開班時間:2021-03-22(杭州)
開班盛況開班時間:2021-04-26(北京)
開班盛況開班時間:2021-05-10(北京)
開班盛況開班時間:2021-02-22(北京)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2020-09-21(上海)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2019-07-22(北京)
開班盛況Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號