第一次用SpringMvc好奇的并非Spring MVC完成参数绑定的过程,而是好奇,Spring如何获取到方法的形参名,并完成属性注入,下面就简单的分析下。
@RestController
public class FooController {
@GetMapping("/methodOne")
public Boolean methodOne(Integer filedOne, String fieldTwo) {
System.out.println(filedOne);
System.out.println(fieldTwo);
return Boolean.TRUE;
}
}
有两个参数,分别为filedOne(Integer),fieldTwo(String)。
一个Spring MVC的应用,当有一个Web请求的进来的时候,我们一般从org.springframework.web.servlet.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;
//获取请求对应的处理器和拦截器链(1)
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//遍历系统中存在的处理适配器,一旦匹配到直接就返回了(2)
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//执行接口方法,返回视图对象(3)
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);
}
}
}
重点看mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
调用HandlerAdapter的handle方法,实际上会进入到RequestMappingHandlerAdapter(实现了HandlerAdapter)
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
// 判断当前是否需要支持在同一个session中只能线性地处理请求
if (this.synchronizeOnSession) {
// 获取当前请求的session对象
HttpSession session = request.getSession(false);
// 为当前session生成一个唯一的可以用于锁定的key
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
// 对HandlerMethod进行参数等的适配处理,并调用目标handler
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 如果当前不存在session,则直接对HandlerMethod进行适配
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
// 判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理,
// 为其设置过期时间
if (!response.containsHeader("Cache-Control")) {
// 如果当前SessionAttribute中存在配置的attributes,则为其设置过期时间。
// 这里SessionAttribute主要是通过@SessionAttribute注解生成的
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
// 如果当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,
// 如果存在,则按照该设置进行response处理,如果不存在,则设置response中的
// Cache的过期时间为-1,即立即失效
this.prepareResponse(response);
}
}
return mav;
}
上述代码主要做了两部分处理:
①判断当前是否对session进行同步处理,如果需要,则对其调用进行加锁,不需要则直接调用;
②判断请求头中是否包含Cache-Control请求头,如果不包含,则设置其Cache立即失效。
HandlerMethod的具体处理是在invokeHandlerMethod()方法中进行的,如下是该方法的具体实现
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中
// 配置的InitBinder,用于进行参数的绑定
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 获取容器中全局配置的ModelAttribute和当前当前HandlerMethod所对应的Controller
// 中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 将handlerMethod封装为一个ServletInvocableHandlerMethod对象,
// 该对象用于对当前request的整体调用流程进行了封装
ServletInvocableHandlerMethod invocableMethod =
createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 设置当前容器中配置的所有ArgumentResolver
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 设置当前容器中配置的所有ReturnValueHandler
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 将前面创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
invocableMethod.setDataBinderFactory(binderFactory);
// 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 这里initModel()方法主要作用是调用前面获取到的@ModelAttribute标注的方法,
// 从而达到@ModelAttribute标注的方法能够在目标Handler调用之前调用的目的
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 获取当前的AsyncWebRequest,这里AsyncWebRequest的主要作用是用于判断目标
// handler的返回值是否为WebAsyncTask或DefferredResult,如果是这两种中的一种,
// 则说明当前请求的处理应该是异步的。所谓的异步,指的是当前请求会将Controller中
// 封装的业务逻辑放到一个线程池中进行调用,待该调用有返回结果之后再返回到response中。
// 这种处理的优点在于用于请求分发的线程能够解放出来,从而处理更多的请求,只有待目标任务
// 完成之后才会回来将该异步任务的结果返回。
AsyncWebRequest asyncWebRequest = WebAsyncUtils
.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 封装异步任务的线程池,request和interceptors到WebAsyncManager中
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 这里就是用于判断当前请求是否有异步任务结果的,如果存在,则对异步任务结果进行封装
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)
asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
// 封装异步任务的处理结果,虽然封装的是一个HandlerMethod,但只是Spring简单的封装
// 的一个Callable对象,该对象中直接将调用结果返回了。这样封装的目的在于能够统一的
// 进行右面的ServletInvocableHandlerMethod.invokeAndHandle()方法的调用
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,
// 还会判断是否需要将FlashAttributes封装到新的请求中
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
// 调用request destruction callbacks和对SessionAttributes进行处理
webRequest.requestCompleted();
}
}
上述代码是RequestMappingHandlerAdapter处理请求的主要流程,其主要包含四个部分:
①获取当前容器中使用@InitBinder注解注册的属性转换器;
②获取当前容器中使用@ModelAttribute标注但没有使用@RequestMapping标注的方法,并且在调用目标方法之前调用这些方法;
③判断目标handler返回值是否使用了WebAsyncTask或DefferredResult封装,如果封装了,则按照异步任务的方式进行执行;
④处理请求参数,调用目标方法和处理返回值
invocableMethod = invocableMethod.wrapConcurrentResult(result);
invocableMethod方法:
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//对目标handler的参数进行处理,并且调用目标handler
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
//...(省略)
}
直接进入invokeForRequest方法
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 将request中的参数转换为当前handler的参数形式
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
//...(省略)
}
最重要方法getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//获取当前handler所声明的所有参数,主要包括参数名,参数类型,参数位置,所标注的注解等等属性
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// providedArgs是调用方提供的参数,这里主要是判断这些参数中是否有当前类型
// 或其子类型的参数,如果有,则直接使用调用方提供的参数,对于请求处理而言,默认情况下,
// 调用方提供的参数都是长度为0的数组
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 如果能够找到对当前参数进行处理的ArgumentResolver,则调用其
// resolveArgument()方法从request中获取对应的参数值,并且进行转换
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (this.logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
到这边就已经获取到了我们传进来的参数
MethodParameter[] parameters = getMethodParameters();
今天就先分析到这,有借鉴别人的文章。大家多多包涵