DispatcherServlet調用點方法
// 上層的調用方法為AbstractApplicationContext#refresh()---》onRefresh();
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* 初始化解析器、映射器含长,適配器等等券腔,根據/org/springframework/web/servlet/DispatcherServlet.properties 配置文件初始化
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
最主要的處理方法
doDispatch(HttpServletRequest request, HttpServletResponse response)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
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);
// 1.為當前的請求匹配對應的處理Handler,其實也就是根據url去匹配要執(zhí)行Controller哪個方法.詳見 解釋1
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//2.確定當前請求的適配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
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;
}
}
// 3 前置通知器 HandlerInterceptor
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4.實際執(zhí)行
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//5. 后置過濾攔截
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//6.視圖渲染、返回值處理
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()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
- 解釋1
getHandler()-->AbstractHandlerMethodMapping#getHandlerInternal(HttpServletRequest request)拘泞。把HandlerMapping封裝成HandlerExecutionChain
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
** url 映射method在容器初始化的時候已經準備好**
// 入口 開始聲明的initStrategies() -->initHandlerMappings(context);會山路十八彎的調到
AbstractHandlerMethodMapping#initHandlerMethods() {
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
-- isHandler(beanType)判斷是否有@Controller || @RequestMapping注解
//detectHandlerMethods 方法內
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
// 執(zhí)行完上述方法之后methods 纷纫,Controller內帶有RequestMapping的method為key, @RequestMapping封裝成RequestMappingInfo為value
Map<Method, T> methods =
{
public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.login(java.lang.String,java.lang.String,org.springframework.ui.Model)={[/login],methods=[POST]}
, public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.home(org.springframework.ui.Model)={[/home],methods=[GET]},
public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.logOut()={[/logout]},
public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.layui()={[/layui]}
}
// 循環(huán)methods Map 構造另一種形式的map
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 添加到registry
this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
// 最終模樣
Map<T, MappingRegistration<T>> registry =
{
{[/login],methods=[POST]}=org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistration@81e87eb
, {[/home],methods=[GET]}=org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistration@6bb30dc5
}
AbstractHandlerMethodMapping$MappingRegistration {
directUrls = [/login],
handlerMethod = public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.login(java.lang.String,java.lang.String,org.springframework.ui.Model),
mapping = {[/login],methods=[POST]},
mappingName = LC#login
}
-
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());用到了策略模式去匹配對應的
HandlerAdapter一共有三種,即下圖所示陪腌。作用就是去使用哪一種類型去處理請求辱魁。下面4中所示。
前置過濾器攔截
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
- 實際執(zhí)行
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
ServletInvocableHandlerMethod#invokeAndHandle
4.1 調用 InvocableHandlerMethod#invokeForRequest
4.1.1Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);InvocableHandlerMethod.getMethodArgumentValues(request, mavContainer, providedArgs);策略模式獲取hand中方法的入參數(shù)組
4.1.2 Object returnValue = doInvoke(args); 反射調用hand中的method
4.2 調用this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);對method的返回參數(shù)進行處理诗鸭,也是策略模式染簇。 - 后置過濾攔截器 mappedHandler.applyPostHandle(processedRequest, response, mv);
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);視圖渲染、返回值處理
6.1 render(mv, request, response);
6.2 mappedHandler.triggerAfterCompletion(request, response, null);后置過濾器强岸,釋放資源锻弓,關閉連接
---未完待續(xù) ,后續(xù)把圖補上。