Spring MVC请求参数的深入解析

网友投稿 645 2023-01-23

Spring MVC请求参数的深入解析

Spring MVC请求参数的深入解析

请求参数解析

客户端请求在handlerMapping中找到对应handler后,将会继续执行DispatchServlet的doPatch()方法

首先是找到handler对应的适配器。

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

进入到getHandlerAdapter(mappedHandler.getHandler())方法中

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

if (this.handlerAdapters != null) {

for (HandlerAdapter adapter : this.handlerAdapters) {

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");

}

这里存在多个适配器,如图:

其中使用@RequestMaping注解修饰的控制器都将适配第一个适配器;而函数式方法将会使用第二个适配器。

跟踪请求,这里将会获得第一个适配器,判断也简单,如下:

public final boolean supports(Object handler) {

return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));

}

如果是HandlerMethod类型的处理器就采用这个适配器,而客户端请求正好对应的是HandlerMethod处理器。

找到适配器后,将会真正执行处理器逻辑。如下:

// Actually invoke the handler.

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

进入RequestMappingHandlerAdapter,执行适配器核心方法:

@Override

protected ModelAndView handleInternal(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;

checkRequest(request);

// Execute invokeHandlerMethod in synchronized block if required.

if (this.synchronizeOnSession) {

HttpSession session = request.getSession(false);

if (session != null) {

Object mutex = WebUtils.getSessionMutex(session);

synchronized (mutex) {

mav = invokeHandlerMethod(request, response, handlerMethod);

}

}

else {

// No HttpSession available -> no mutex necessary

mav = invokeHandlerMethod(request, response, handlerMethod);

}

}

else {

// No synchronization on session demanded at all...

mav = invokeHandlerMethod(request, response, handlerMethod);

}

if (!response.containsHeader(HEADER_CACHE_CONTROL)) {

if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);

}

else {

prepareResponse(response);

}

}

return mav;

}

其核心代码为实际执行处理器方法:

mav = invokeHandlerMethod(request, response, handlerMethod);

同样,我们打开RequestMappingHandlerAdapter中的invokeHandlerMethod方法:

@Nullable

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ServletWebRequest webRequest = new ServletWebRequest(request, response);

try {

//通过处理器获得真正的执行方法及其参数列表

ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);

//给执行方法对象添加参数解析器

if (this.argumentResolvers != null) {

invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);

}

//给执行方法对象添加返回值处理器

if (this.returnValueHandlers != null) {

invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

}

//处理器对象装配完成,执行控制器方法

invocableMethod.invokeAndHandle(webRequest, mavContainer);

if (asyncManager.isConcurrentHandlingStarted()) {

return null;

}

return getModelAndView(mavContainer, modelFactory, webRequest);

}

finally {

webRequest.requestCompleted();

}

}

在这个关键方法中,首先执行请求对应的控制器逻辑,之后进行系列处理,根据返回值处理器处理返回值。

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {

//执行控制器方法

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

setResponseStatus(webRequest);

if (returnValue == null) {

if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {

disableContentCachingIfNecessary(webRequest);

mavContainer.setRequestHandled(true);

return;

}

}

else if (StringUtils.hasText(getResponseStatusReason())) {

mavContainer.setRequestHandled(true);

return;

}

mavContainer.setRequestHandled(false);

http:// Assert.state(this.returnValueHandlers != null, "No return value handlers");

try {

//处理返回值

this.returnValueHandlers.handleReturnValue(

returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

}

catch (Exception ex) {

if (logger.isTraceEnabled()) {

logger.trace(formatErrorForReturnValue(returnValue), ex);

}

throw ex;

}

}

以下给出部分参数解析器及返回值处理器截图:

参数解析器。对应每一个参数(路径变量、矩阵变量、获得请求头、请求域等)的获取方式

返回值处理器。ModelAndView、ResponseBody等。每个处理器处理不同类别的返回值类型。

接下来,真正进入到最终执行method方法invocableMethod.invokeAndHandle(webRequest, mavContainer);,这里是真是执行控制器中映射的方法。

以下为获得参数列表对应值的逻辑,参数获取完成后将会执行真正的控制器逻辑。

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {

//通过参数解析器获取参数列表每一个参数的值

Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

if (logger.isTraceEnabled()) {

logger.trace("Arguments: " + Arrays.toString(args));

}

return doInvoke(args);

}

进入解析逻辑,解析是对比每一个参数绑定的注解,如果注解一致将会使用对应的解析器将请求传递的参数值获取到。

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {

//获得控制器参数列表,每一个参数包含其参数类型,参数次序、注解修饰(用于使用对应解析器)

MethodParameter[] parameters = getMethodParameters();

if (ObjectUtils.isEmpty(parameters)) {

return EMPTY_ARGS;

}

Object[] args = new Object[parameters.length];

for (int i = 0; i < parameters.length; i++) {

//轮循获得参数

MethodParameter parameter = parameters[i];

parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);

args[i] = findProvidedArgument(parameter, providedArgs);

if (args[i] != null) {

continue;

}

//判断解析器是否支持当前参数的解析

if (!this.resolvers.supportsParameter(parameter)) {

throw new IllegalStateException(formatArguhttp://mentError(parameter, "No suitable resolver"));

}

try {

//获得参数值的核心方法

args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);

}

catch (Exception ex) {

// Leave stack trace for later, exception may actually be resolved and handled...

if (logger.isDebugEnabled()) {

String exMsg = ex.getMessage();

if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {

logger.debug(formatArgumentError(parameter, exMsg));

}

}

throw ex;

}

}

return args;

}

查看解析器是否指出当前参数部分代码,可以了解到SpringMVC的缓存策略。

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {

//从缓存中获取当前参数的解析器

HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);

//缓存中不存在则将这个参数对应的解析器加到缓存中,提升后续相同请求响应速度。

if (result == null) {

for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {

if (resolver.supportsParameter(parametOTafZmer)) {

result = resolver;

this.argumentResolverCache.put(parameter, result);

break;

}

}

}

return result;

}

参数列表

以下为获得的参数列表第一个参数部分属性

其对应的是控制器中id参数:

@GetMapping(value = "/student01/{id}/car/{name}")

public Map testAnnotation(@PathVariable(name = "id") String id){

Map map = new HashMap<>();

map.put("id", id);

return map;

}

以上即为获得请求Handler对应的适配器,处理参数映射、执行控制器逻辑、返回值处理的核心源码处理。

总结

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:上门服务app运营模式(上门服务app运营模式是什么)
下一篇:云桌面云储存云应用云安全(云桌面安全管控)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~