有道无术,术尚可求,有术无道,止于术。
Spring MVC:5.3.20
文章目录
-
- 前言
-
- 获取处理适配器
-
- 进入适配器处理方法
-
- 参数解析器处理参数
-
- 3.1 27种参数解析器
- 3.2 缓存
- 3.3 执行参数解析
- 3.4 反射执行控制器方法
前言
在之前我们分析了Spring MVC
支持多种方式将请求参数封装到对应的控制器方法参数中=》Spring MVC系列(3)- 获取请求参数的多种方式。
也简单分析了,请求进来都是由DispatcherServlet
来进行处理的=》Spring MVC系列(7)-DispatcherServlet处理请求流程源码分析。
接下来我们以一个简单的控制类分析下Spring MVC
处理参数的源码。
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/test")
public String test(@RequestParam("name") String name) {
return name;
}
}
1. 获取处理适配器
在DispatcherServlet
的doDispatch()
中,首先会获取映射处理器,也就是根据请求路径,获取到对应的控制器Controller
中的方法,比如:
http://localhost:8080/test/test?name=zhangsan
=》 org.pearl.boot.tstudy.controller.TestController#test(String)
接着DispatcherServlet
会根据处理器来获取处理适配器HandlerAdapter
,由他它调用具体的方法对用户发来的请求来进行处理,源码如下:
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
在getHandlerAdapter
方法中,会循环所有的适配器,找到能处理该请求的适配器并返回。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
// 1. 循环所有处理适配器
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
// 2. 找到能处理该请求的适配器并返回
HandlerAdapter adapter = (HandlerAdapter)var2.next();
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");
}
HandlerAdapter
接口源码如下:
public interface HandlerAdapter {
// 判断是否支持传入的handler
boolean supports(Object handler);
// 使用handler处理请求
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 获取资源的LastModified值
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerAdapter
实现类,代表了每一种类型的适配器,主要有四种:
- RequestMappingHandlerAdapter:支持标注了@RequestMapping方法
- HandlerFunctionAdapter:处理 HandlerFunction 类型的接口方法(函数式编程)
- HttpRequestHandlerAdapter:处理实现了 HttpRequestHandler 接口的方法
- SimpleControllerHandlerAdapter:主要用来处理实现了 Controller 接口的方法
因为案例中使用的@GetMapping("/test")
,所以获取到的适配器是RequestMappingHandlerAdapter
。
2. 进入适配器处理方法
接着适配器就进入到其handle
方法处理了。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
handle
方法进入到RequestMappingHandlerAdapter
的handleInternal
方法进行处理。
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 1. 检查请求方式和Session
this.checkRequest(request);
ModelAndView mav;
// 2. 是否开启了Session并发控制,开了会进入到同步锁中
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 3. 执行目标方法
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
handleInternal
方法进入到invokeHandlerMethod
方法中,执行目标方法。
@Nullable
// HandlerMethod =》org.pearl.boot.tstudy.controller.TestController#test(String)
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 1. 将Request和Response进行封装
ServletWebRequest webRequest = new ServletWebRequest(request, response);
Object result;
try {
// 2. 获取WebDataBinderFactory 工厂对象,工厂创建WebDataBinder对象,WebDataBinder的作用就是把web请求的parameters绑定到JavaBean
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
// 3. 获取ModelFactory 工厂对象,他的主要作用是初始化Model和将Model中的参数更新到SessionAttributes中
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
// 4. 创建InvocableHandlerMethod对象,用于调用处理器方法,处理给定的请求
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
// 4.1 设置参数解析器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 4.2 设置返回值解析器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 4.3 设置数据绑定工厂
invocableMethod.setDataBinderFactory(binderFactory);
// 4.4 设置ParameterNameDiscoverer,发现方法和构造函数的参数名
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 5. 创建ModelAndView容器,主要是用来返回Model对象
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 5.1 添加属性
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 5.2 初始化Model
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 5.3 如果控制器方法重定向时,默认的Model是否使用
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 6. 封装为异步请求
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 6.1 获取异步管理器,支持异步请求处理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 7. 执行处理器
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (!asyncManager.isConcurrentHandlingStarted()) {
// 8. 返回ModelAndView实例, 后面进行视图解析
ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
return var15;
}
result = null;
} finally {
webRequest.requestCompleted();
}
return (ModelAndView)result;
}
invokeHandlerMethod
方法中,最重要的就是invokeAndHandle
方法。
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1. 处理请求并返回
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态为200
this.setResponseStatus(webRequest);
// 2. 处理返回值
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
this.disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 3. 返回值处理器
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (logger.isTraceEnabled()) {
logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
invokeAndHandle
方法中会调用invokeForRequest
方法处理请求
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1. 获取方法参数对应的值
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 2. 执行控制器上的方法
return this.doInvoke(args);
}
invokeForRequest
方法就是处理参数的核心方法,调用参数解析器对参数处理。
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1. 获取方法中的参数集合
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);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
// 2. 参数解析器不支持该参数解析,抛出IllegalStateException
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 3. 调用参数解析器解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
// 4. 返回参数
return args;
}
}
在this.getMethodParameters()
方法中,获取MethodParameter
集合,每一个MethodParameter
对象都封装了该请求方法的参数位置(0开始)、类型、标识注解等信息,比如public String test(@RequestParam("name") String name)
方法获取到的MethodParameter
集合如下所示:
3. 参数解析器处理参数
this.resolvers.resolveArgument
会进行参数解析,可以看到resolvers
中包含了27种类型的参数解析器和缓存。
3.1 27种参数解析器
参数解析器的顶级接口为HandlerMethodArgumentResolver
,声明了两个方法,源码如下:
public interface HandlerMethodArgumentResolver {
// 是否支持该类型MethodParameter 解析
boolean supportsParameter(MethodParameter parameter);
// 解析参数
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
默认这里显示的有27个,我们也可以自定义参数解析器:
比如常见的解析器有:
- RequestParamMethodArgumentResolver:解析@RequestParam 注解的参数
- PathVariableMethodArgumentResolver:将请求URL中的模板变量映射到接口方法的参数解析器,@PathVariable注解
- RequestHeaderMethodArgumentResolver:标记了@RequestHeader注解,解析请求头参数绑定到接口参数上
3.2 缓存
argumentResolverCache
是一个ConcurrentHashMap
类型的缓存,将方法参数对象和对应的解析器缓存起来,第一次解析后放入缓存,第二次再请求该方法就从缓存中获取解析器,提高效率。
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap(256);
3.3 执行参数解析
执行参数解析时,首先会获取到该参数的解析器,首先在缓存中获取,没有的话,就会循环所有的解析器,直到找到一个支持该参数的解析器,然后再放入到缓存中。
接着开始解析参数,因为我们案例使用的是@RequestParam
注解,所以获取到的是RequestParamMethodArgumentResolver
解析器
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 1. 获取该参数的解析器
HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
} else {
// 2. 解析并返回
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
RequestParamMethodArgumentResolver
解析参数源码如下:
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 1. 获取RequestParam注解信息,包含参数的名称,是否必须
AbstractNamedValueMethodArgumentResolver.NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
// 2. 通过表达式获取到方法参数上的名称
Object resolvedName = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
// 3. 没有根据RequestParam注解 找到对应的参数,抛出IllegalArgumentException
if (resolvedName == null) {
throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");
} else {
// 4.1 根据名称从请求中获取值,@RequestParam("name") String name=》zhangsan
Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
// 4.2 没拿到,看是否有默认值
if (namedValueInfo.defaultValue != null) {
arg = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
} else if (namedValueInfo.required && !nestedParameter.isOptional()) {
// 4.3 没拿到,又是必填项,抛出异常
this.handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
// 4.4 没有必填 也没有默认值,处理Null值
arg = this.handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
} else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
// 4.5 为空并且存在默认值,则处理空值
arg = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
}
// 5. 处理参数绑定
if (binderFactory != null) {
// 5.1 工厂创建WebDataBinder 对象,可以对参数进行转换,然后绑定
WebDataBinder binder = binderFactory.createBinder(webRequest, (Object)null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
} catch (ConversionNotSupportedException var11) {
throw new MethodArgumentConversionNotSupportedException(arg, var11.getRequiredType(), namedValueInfo.name, parameter, var11.getCause());
} catch (TypeMismatchException var12) {
throw new MethodArgumentTypeMismatchException(arg, var12.getRequiredType(), namedValueInfo.name, parameter, var12.getCause());
}
if (arg == null && namedValueInfo.defaultValue == null && namedValueInfo.required && !nestedParameter.isOptional()) {
this.handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
}
}
this.handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
// 6. 返回参数值
return arg;
}
}
在请求中获取到该参数对应的请求值:
@Nullable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
// 1. 获取HttpServletRequest
HttpServletRequest servletRequest = (HttpServletRequest)request.getNativeRequest(HttpServletRequest.class);
Object arg;
if (servletRequest != null) {
// 2. 调用方法,获取到文件参数,如果没有,则返回一个new Object
arg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
// 3. 存在文件参数,直接返回
if (arg != MultipartResolutionDelegate.UNRESOLVABLE) {
return arg;
}
}
arg = null;、
// 4. 获取文件参数
MultipartRequest multipartRequest = (MultipartRequest)request.getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
// 5. 存在文件则获取文件流并转为MultipartFile对象
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = files.size() == 1 ? files.get(0) : files;
}
}
// 6. 没有文件则根据参数名称,从request中拿到参数对应的值
if (arg == null) {
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = paramValues.length == 1 ? paramValues[0] : paramValues;
}
}
// 7. 返回参数对应的值
return arg;
}
3.4 反射执行控制器方法
最后,通过反射执行控制器中的方法,并将参数值传递过去,整个参数处理的流程就结束了:
@Nullable
protected Object doInvoke(Object... args) throws Exception {
// 1. 获取执行的方法
Method method = this.getBridgedMethod();
try {
// 2. 执行方法,进入到控制器方法中(反射),参数也带过去了。
return KotlinDetector.isSuspendingFunction(method) ? CoroutinesUtils.invokeSuspendingFunction(method, this.getBean(), args) : method.invoke(this.getBean(), args);
} catch (IllegalArgumentException var5) {
this.assertTargetBean(method, this.getBean(), args);
String text = var5.getMessage() != null ? var5.getMessage() : "Illegal argument";
throw new IllegalStateException(this.formatInvokeError(text, args), var5);
} catch (InvocationTargetException var6) {
// ....
}
}
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: