Spring Mvc源码分析
- mvc源码图解
springmvc经过一系列的调用到DispatcherServlet类的doService方法,调用doDispatch方法
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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//判断请求是否时文件类型
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//获取handler,得到过滤器链和handler(里面就包含了 真正要调用的方法)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//通过handler获取HandlerAdapter,这里是注解,所以我们获取到的是//HttpRequestHandlerAdapter,下面就用得到的HttpRequestHandlerAdapter处理拦截器
//和实际方法的调用
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用拦截器的preHandler,如果返回false,则调用结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//处理实际方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//调用拦截器的postHandler方法
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);
}
//处理异常,如果我们配置了统一异常,就在这里执行,并会执行拦截器的afterCompletion方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//执行拦截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//执行拦截器的afterCompletion方法,到这就会发现afterCompletion方法总是会执行
//所以afterCompletion方法中可以关闭流或者链接
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);
}
}
}
}
getHandler方法,得到HandlerExecutionChain,前提是url匹配到了路径,就是@Controller中的@RequestMapping被匹配到,如果匹配不到handler为null
image.png
getHandlerAdapter方法,获取处理getHandler返回的HandlerExecutionChain,我们得到的是
HttpRequestHandlerAdapter
image.png
applyPreHandler方法,调用实际方法之前先调用拦截器的preHandler方法
image.png
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
通过debug方式最终调用到RequestMappingHandlerAdapter#handleInternal方法
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
//因为session是线程不安全,这里处理多个线程同时访问的安全问题
//默认为false
if (this.synchronizeOnSession) {
//获取session,如果没有不创建session
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
//多个线程,同时只处理一个,保证线程安全
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
//如果没有session
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
// invokeHandlerMethod方法调用我们实际的要调用的方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
invokeHandlerMethod
--invocableMethod.invokeAndHandle(webRequest, mavContainer);代码
--> invokeAndHandle 方法中的 returnValue = invokeForRequest(webRequest,
mavContainer,providedArgs);代码
,其余的我也没自己看过那我们就看一看invokeForRequest方法
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//解析实际调用方法上的变量赋值,像我们比较常用的GET请求路径赋值变量@PathVariable //POST请求的@RequestBody 还有继承HandlerMethodArgumentResolver接口, //supportsParameter方法判断方法的入参是否是某个类,如果是返回true在resolveArgument方法
//将类赋值,经常的用法是权限登入,在系统中保存当前登入人的信息,User类,在方法中入参包含//User类,就会自动的赋值上,当然继承HandlerMethodArgumentResolver类要放到//HandlerMethodArgumentResolver中,会在下面用图片展示一下
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
//真正调用方法
return this.doInvoke(args);
}
如何用HandlerMethodArgumentResolver将变量赋值到方法的入参里
image.png
image.png
image.png
image.png
image.png
image.png
网友评论