DispatcherServlet 處理流程
上一節(jié)講了Spring容器啟動(dòng),會(huì)把url與類方法的映射關(guān)系保存起來侄榴,這一節(jié)允扇,就能看到它的作用啦之众。
DispatcherServlet是整個(gè)SpringMVC的核心,負(fù)責(zé)請(qǐng)求處理以及返回響應(yīng)的工作蝇率。直奔主題迟杂,找到DispatcherServlet類,再找到該類下的doService()方法本慕,關(guān)鍵代碼:
try {
doDispatch(request, response);
}
點(diǎn)擊這個(gè)孤獨(dú)的方法排拷,進(jìn)去,上核心馬:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
// 定義handler執(zhí)行鏈锅尘,重要
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
ModelAndView mv = null;
// 檢查是否是文件請(qǐng)求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 獲取當(dāng)前請(qǐng)求的handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 獲取當(dāng)前請(qǐng)求的適配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 判斷get方法是否有修改监氢,沒有直接返回
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;
}
// hander實(shí)際執(zhí)行
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
applyDefaultViewName(processedRequest, mv);
// handler后置處理
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 處理分發(fā)后的結(jié)果
processDispatchResult(processedRequest, response, mappedHandler, mv,
dispatchException);
}
看到那個(gè)閃亮的方法沒 - getHandler(processedRequest),點(diǎn)擊進(jìn)去鉴象,上馬:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// 從handlerMappings 獲取并構(gòu)建請(qǐng)求的執(zhí)行鏈
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
打個(gè)debug忙菠,看下handlerMappings里面是啥
看到?jīng)],這不就是上一節(jié)講到的東東咩纺弊?
再點(diǎn)擊 mapping.getHandler(request)方法進(jìn)去牛欢,看看有啥:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 獲取handler
Object handler = getHandlerInternal(request);
……
// 是beanName獲取對(duì)應(yīng)的bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
……
// 構(gòu)建handler的執(zhí)行鏈
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
……
return executionChain;
}
getHandlerInternal(request) 是重點(diǎn),點(diǎn)進(jìn)去:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 獲取訪問路徑淆游,如 /test/hello
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
// 查找訪問路徑對(duì)應(yīng)的處理方法
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
快到了傍睹!繼續(xù)點(diǎn)擊 lookupHandlerMethod(lookupPath, request)隔盛,進(jìn)入:
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 根據(jù)訪問路徑匹配請(qǐng)求方法
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
// 根據(jù)找到的信息,封裝 matches
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
// 省略查找最近匹配內(nèi)容
……
// 返回 handlerMethod
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
點(diǎn)擊this.mappingRegistry.getMappingsByDirectPath(lookupPath)拾稳,進(jìn)入:
public List<T> getMappingsByDirectPath(String urlPath) {
return this.pathLookup.get(urlPath);
}
看到了沒吮炕,pathLookup登場了,T 類型是 RequestMappingInfo访得。
這一步龙亲,就能找到 handlerMethod了,也就是訪問路徑對(duì)應(yīng)的處理方法悍抑。所以上面的getHandler() 方法就能返回對(duì)應(yīng)的 HandlerExecutionChain鳄炉。
回到 doDispatch()方法中,既然拿到了 handlerMethod搜骡,后面就是做了一些錦上添花的事拂盯,最后調(diào)用該方法了。
不講了记靡,口渴谈竿,飲杯開水去~~