SpringMVC處理流程非常詳細(xì)的講解
作者:Springboot實戰(zhàn)案例錦集
通過HandlerMapping找到了相應(yīng)的HandlerMethod對象,最后封裝到了HandlerExecutionChain中,接下來就是根據(jù)HandlerMethod查找合適的HandlerAdapter處理程序。
1 請求入口
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 2.1.通過HandlerMapping獲取請求處理鏈,該對象由處理程序(Controller,一般HandlerMethod對象)及攔截器(Interceptor)組成
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2.2.根據(jù)2.1獲取的處理程序(HandlerMethod)對象確定能夠處理該處理程序的HandlerAdapter對象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ...
// 2.3.執(zhí)行處理程序之前,執(zhí)行攔截器preHandle方法,如果返回了false,本次請求將被終止
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 2.4.真正的執(zhí)行處理程序
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// ...
// 2.5.執(zhí)行處理程序之后,執(zhí)行攔截器postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 2.6.處理結(jié)果,根據(jù)處理程序是否發(fā)生異常,是否返回有ModelAndView對象進行結(jié)果的處理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
// ...
}
}
2 處理請求
2.1 獲取請求處理鏈
該步驟通過HandlerMapping獲取HandlerExecutionChain處理器執(zhí)行鏈。
public class DispatcherServlet {
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍歷當(dāng)前容器中注冊的所有HandlerMapping對象
for (HandlerMapping mapping : this.handlerMappings) {
// 針對Controller接口,使用的是RequestMappingHandlerMapping對象
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
}
這里以RequestMappingHandlerMapping為例
mapping.getHandler(request)方法調(diào)用流程如下:
public abstract class AbstractHandlerMapping {
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 調(diào)用子類實現(xiàn)的getHandlerInternal方法
Object handler = getHandlerInternal(request);
// ...
// 根據(jù)查找到的處理程序封裝到處理程序執(zhí)行鏈
// 這里會將攔截器也添加其中
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ...這里是跨域相關(guān)的配置
return executionChain;
}
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);
}
}
return chain;
}
}
調(diào)用子類RequestMappingInfoHandlerMapping#getHandlerInternal實現(xiàn)。
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
// 又調(diào)父類的實現(xiàn) (⊙o⊙)…
return super.getHandlerInternal(request);
}
}
}
調(diào)用父類AbstractHandlerMethodMapping#getHandlerInternal方法
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
private final MappingRegistry mappingRegistry = new MappingRegistry();
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 根據(jù)當(dāng)前的請求獲取請求的uri
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 系統(tǒng)啟動時初始化RequestMappingHandlerMapping解析了整個系統(tǒng)中所有的Controller然后注冊到MappingRegistry中
// 根據(jù)當(dāng)前的請求uri,對應(yīng)List<RequestMappingInfo>對象,相同的uri可能對應(yīng)不同的request method,所以這里返回的是List集合
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
// 該方法內(nèi)部會根據(jù)找到的RequestMappingInfo進行遍歷,根據(jù)請求信息逐個的判斷對應(yīng)@RequestMapping配置的屬性是否匹配
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
// 下面if的邏輯就是判斷如果找到了匹配并且存在多個會找出最合適的
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (CorsUtils.isPreFlightRequest(request)) {
for (Match match : matches) {
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
} else {
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
// 將當(dāng)前請求uri保存到request對象中setAttribute
handleMatch(bestMatch.mapping, lookupPath, request);
// 返回當(dāng)前uri對應(yīng)的HandlerMethod對象
return bestMatch.getHandlerMethod();
}
}
protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) {
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
}
}
2.2 獲取HandlerAdapter
在上一步中通過HandlerMapping找到了相應(yīng)的HandlerMethod對象,最后封裝到了HandlerExecutionChain中,接下來就是根據(jù)HandlerMethod查找合適的HandlerAdapter處理程序。
public class DispatcherServlet {
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
// 這里的參數(shù)handler一般都是HandlerMethod對象
for (HandlerAdapter adapter : this.handlerAdapters) {
// 這個根據(jù)handler判斷哪個HandlerAdapter支持,一般都是RequestMappingHandlerAdapter
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
}
RequestMappingHandlerAdapter 這調(diào)用的是父類方法
public abstract class AbstractHandlerMethodAdapter {
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
}
public class RequestMappingHandlerAdapter {
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
}
2.3 執(zhí)行攔截器preHandle方法
在真正調(diào)用處理程序前,執(zhí)行攔截器preHandle方法
public class HandlerExecutionChain {
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
// 如果任何一個攔截器返回了false,本次請求都會被終止
if (!interceptor.preHandle(request, response, this.handler)) {
// 該攔截器的完成回調(diào)會被執(zhí)行
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
}
2.4 實際請求處理
public class DispatcherServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
}
AbstractHandlerMethodAdapter
public abstract class AbstractHandlerMethodAdapter {
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 子類重寫了該方法
return handleInternal(request, response, (HandlerMethod) handler);
}
}
RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter {
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
if (this.synchronizeOnSession) {
// ...
} else {
// No synchronization on session demanded at all...
// 執(zhí)行HandlerMethod調(diào)用
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// ...
return mav;
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 創(chuàng)建數(shù)據(jù)綁定工廠,主要作用就是將請求的參數(shù)信息與Controller方法的參數(shù)進行綁定(數(shù)據(jù)類型的轉(zhuǎn)換)及參數(shù)校驗
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 處理@ModelAttribute和@SessionAttribute注解,它將做兩件事:
// 1.將@SessionAttribute注解的方法的相關(guān)數(shù)據(jù)合并到下面的ModelAndViewContainer中
// 2.將@ModelAttribute注解的方法返回值添加到ModelAndViewContainer中
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 實際HandlerMethod調(diào)用對象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 設(shè)置參數(shù)解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 設(shè)置Controller方法返回值的處理器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 執(zhí)行上面說的兩個步驟
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// ...
// 執(zhí)行調(diào)用HandlerMethod
// 在這個過程中會應(yīng)用到參數(shù)解析器和返回值處理器,這里就不展開說了
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 這里會返回ModelAndView對象,這個根據(jù)情況,如果你是RestController,那么在通過返回值處理器就已經(jīng)將結(jié)果進行了輸出如使用@ResponseBody注解的方法
// 如果是RestController,請求結(jié)果就提前輸出了,同時會將ModelAndViewContainer的requestHandled屬性設(shè)置為true。
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
// 如果是@ResponseBody注解的方法,那么直接返回null
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
// ...
return mav;
}
}
2.5 執(zhí)行攔截器postHandle方法
public class HandlerExecutionChain {
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
2.6 處理結(jié)果
public class DispatcherServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 在處理過程中如果出現(xiàn)了異常會進入這里進行異常處理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 如果Controller方法返回有ModelAndView
if (mv != null && !mv.wasCleared()) {
// 進行視圖的渲染輸出到客戶端
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// 如果是RestController接口,那么上面的代碼都不會執(zhí)行
if (mappedHandler != null) {
// 執(zhí)行攔截器的afterCompletion回調(diào)方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
}
責(zé)任編輯:武曉燕
來源:
實戰(zhàn)案例錦集