前面章节介绍了webmvc的请求流程,客户端第一次请求servlet时,会调用servlet的init()方法(对应执行DispatcherServlet的initStrategies方法),该方法只会初始化一次,init方法初始完之后,紧接着执行service方法,对应DispatcherServlet的doDispatch方法,该方法会对请求参数进行解析,获取到对应handler,对应@Controller里面具体执行的方法,参数解析完成后,然后通过反射的原理调用Controller里面的@RequestMapping映射的method,方法执行完后,最后通过RequestResponseBodyMethodProcessor的handleReturnValue处理方法返回值,然后响应给客户端。
下面是前面测试的Controller
@RequestMapping("/hello")
public String hello() {
return "hello spring boot webmvc";
}
可以看到上面hello方法没有参数,所以内部处理逻辑简单很多,我们现在把hello方法添加一个pojo参数,看一下加完参数之后,内部是怎么处理和解析该参数。
@RequestMapping("/hello")
public Student hello(@RequestBody Student student) {
return student;
}
参数解析主要是通过HandlerMethodArgumentResolverComposite类的resolveArgument方法处理,通过类名,我们可以发现该类是通过组合模式进行实现,该方法的源码如下:
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); // 获取的是RequestResponseBodyMethodProcessor对象
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
上面方法最终进入RequestResponseBodyMethodProcessor类的resolveArgument方法,该方法源码:
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
通过上面的方法解析完参数后,继续执行InvocableHandlerMethod的invokeForRequest方法开始进行方法的调用,可以看下该方法源码:
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); // 这里既是获取解析后的参数,通过上面的resolveArgument方法进行
Object returnValue = doInvoke(args);// 最终执行Method的invoke方法
return returnValue; // 即Controller里method的返回值
}
上面会执行完Controller里对应的method,得到method的返回值后,开始调用HandlerMethodReturnValueHandlerComposite类的handleReturnValue方法,该类和上面参数解析的类类似也是通过组合模式进行实现,该方法源码如下:
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
上面方法最终进入RequestResponseBodyMethodProcessor类型handleReturnValue方法,由此可以发现,RequestResponseBodyMethodProcessor这个类既是对请求参数的解析,同时又对方法处理的返回值进行处理,最终响应给客户端。
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); //将方法处理结果返回给客户端
}