视频课程网站建设,怀化最新消息今天,廊坊市网站,新媒体运营论文参考资料#xff1a;
《SpringMVC源码解析系列》
《SpringMVC源码分析》
《Spring MVC源码》 写在开头#xff1a;本文为个人学习笔记#xff0c;内容比较随意#xff0c;夹杂个人理解#xff0c;如有错误#xff0c;欢迎指正。
前文#xff1a;
《SpringMVC源码
《SpringMVC源码解析系列》
《SpringMVC源码分析》
《Spring MVC源码》 写在开头本文为个人学习笔记内容比较随意夹杂个人理解如有错误欢迎指正。
前文
《SpringMVC源码DispatcherServlet初始化流程》
《SpringMVC源码HandlerMapping加载1》
《SpringMVC源码HandlerMapping加载2》
《SpringMVC源码getHandler、getHandlerAdapter过程》 前文我们已经介绍了doDispatch方法过程中的handler查找、适配器查找以及拦截器preHandle方法的执行本文我们会继续介绍方法的调用。
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 {//检查是否为Multipart请求,如果是则HttpServletRequest转换为MultipartHttpServletRequestprocessedRequest checkMultipart(request);multipartRequestParsed (processedRequest ! request);//1.根据request信息寻找对应的Handler//并返回mappedHeadler,它是一个执行链,包含拦截器和自定义controllermappedHandler getHandler(processedRequest);if (mappedHandler null) {//没有找到Handler则通过response反馈错误信息noHandlerFound(processedRequest, response);return;}// 2.根据当前的handler寻找对应的HandlerAdapterHandlerAdapter ha getHandlerAdapter(mappedHandler.getHandler());// 当前handler处理last-modifiedString 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;}}//3.mappedHandler调用拦截器的preHandler方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 4.HandlerAdapter调用自定义Controller中的方法并返回ModelAndViewmv ha.handle(processedRequest, response, mappedHandler.getHandler());//5.视图解析,为request请求找到视图applyDefaultViewName(processedRequest, mv);//6.调用拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}
} 目录
一、handle 1、AbstractHandlerMethodAdapter#handle 2、RequestMappingHandlerAdapter#handleInternal 3、RequestMappingHandlerAdapter#invokeHandlerMethod 4、ServletInvocableHandlerMethod#invokeAndHandle InvocableHandlerMethod#invokeForRequest 5、RequestMappingHandlerAdapter#getModelAndView
二、RequestBody与ResponseBody 1、接口转换 2、参数解析 2.1、查找解析器 2.2、解析过程 3、返回值处理 3.1、选择处理器 3.2、处理过程
补充 一、handle 1、AbstractHandlerMethodAdapter#handle 这里以AbstractHandlerMethodAdapter类为例可以看到内部实际上是调用了handleInternal方法而这个方法实际上是由子类RequestMappingHandlerAdapter实现的。注意下这里的返回值为ModelAndView Overridepublic final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return handleInternal(request, response, (HandlerMethod) handler);} 2、RequestMappingHandlerAdapter#handleInternal 该方法主要进行了对请求request的相关校验、解析、转换、执行相关的handler的invokeHandlerMethod 并返回对应的数据视图对象。 Overrideprotected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ModelAndView mav;//如果设置supportMethods、requireSession属性需要对其进行校验//如果处理的请求方式不是supportMethods集合支持的抛出异常//或者requireSession为true但是request不包含session同样抛出异常checkRequest(request);// 针对线程不安全的session 提供两种方式 一种是同步 从而保证该会话的用户串行执行请求// 一种是非同步处理请求 不管同步与否最终调用核心方法invokeHandlerMethod 调用HandlerMethodif (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 necessarymav 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;} 3、RequestMappingHandlerAdapter#invokeHandlerMethod 这一步中将HandlerMethod被封装ServletInvocableHandlerMethod包裹上方法执行需要的信息并调用invokeAndHandle方法执行最后通过getModelAndView获取视图。 protected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {//先将请求响应对象包装成ServletWebRequestServletWebRequest webRequest new ServletWebRequest(request, response);try {//获取该方法的所有使用InitBinder注解修饰的方法//包装成WebDataBinderFactory 在handlerMethod执行前调用包含类作用范围的和全局作用范围的WebDataBinderFactory binderFactory getDataBinderFactory(handlerMethod);//获取该方法的所有使用ModelAttribute注解修饰的方法 包装成ModelFactory包含类作用范围的和全局作用范围的ModelFactory modelFactory getModelFactory(handlerMethod, binderFactory);//将HandlerMethod方法包装成ServletInvocableHandlerMethod该对象是InvocableHandlerMethod子类//设置相关的组件 比如设置参数解析组件argumentResolvers和返回结果处理组件returnValueHandlers//绑定组件binderFactory和parameterNameDiscovererServletInvocableHandlerMethod invocableMethod createInvocableHandlerMethod(handlerMethod);invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);invocableMethod.setDataBinderFactory(binderFactory);invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);//创建数据模型和视图的容器对象 见名知义其包含我们所常见的数据和视图对象ModelAndViewContainer mavContainer new ModelAndViewContainer();//对于重定向相关的参数保存需要依赖flashMap对象如果一个请求是重定向请求 则input_flash_map保存重定向入参//如果一个请求需要进行重定向 则参数会存放到output_flash_map中mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));//调用ModelAttribute注解修饰的方法将对应的属性存放到mavContainer 的model中modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);//异步请求处理AsyncWebRequest asyncWebRequest WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);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 ]);}invocableMethod invocableMethod.wrapConcurrentResult(result);}//通过反射执行相关的handlerMethod 涉及参数解析返回值的处理、//invocableMethod已经包含了进行参数解析和返回值处理的组件对象invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}//主要处理sessionAttribute 以及对model中的属性进行属性编辑器的转换处理InitBinder//对于view对象进行逻辑视图到物理视图的转换以及重定向参数的设置return getModelAndView(mavContainer, modelFactory, webRequest);}finally {webRequest.requestCompleted();}} 4、ServletInvocableHandlerMethod#invokeAndHandle 首先调用invokeForRequest进行参数解析与方法调用得到返回值后将其封装入mavContainer中。 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 请求处理Object returnValue invokeForRequest(webRequest, mavContainer, providedArgs);// 返回值处理this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);} InvocableHandlerMethod#invokeForRequest invokeForRequest方法首先解析参数然后反射执行方法。 public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {//调用getMethodArgumentValues进行参数解析Object[] args getMethodArgumentValues(request, mavContainer, providedArgs);//调用doInvoke方法反射执行handler处理器Object returnValue doInvoke(args);return returnValue;} protected Object doInvoke(Object... args) throws Exception {ReflectionUtils.makeAccessible(getBridgedMethod());return getBridgedMethod().invoke(getBean(), args);} 5、RequestMappingHandlerAdapter#getModelAndView 从mavContainer取出结果包装成ModelAndView private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {modelFactory.updateModel(webRequest, mavContainer);if (mavContainer.isRequestHandled()) {return null;}//从mavContainer中取出model ModelMap model mavContainer.getModel();//根据取出的model创建视图对象ModelAndView mav new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());if (!mavContainer.isViewReference()) {mav.setView((View) mavContainer.getView());}//处理redirect请求if (model instanceof RedirectAttributes) {MapString, ? flashAttributes ((RedirectAttributes) model).getFlashAttributes();HttpServletRequest request webRequest.getNativeRequest(HttpServletRequest.class);RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);}return mav;} 二、RequestBody与ResponseBody 以下内容参考自《Spring MVC源码(三) ----- RequestBody和ResponseBody原理解析》 在上文中我们介绍了invokeAndHandle方法其中的两个步骤分别为参数解析与返回值处理这一节我们结合两个常用注解RequestBody与ResponseBody来进行这部分内容的讲解。 首先来看个样例第一个requestBody请求使用RequestBody将HTTP请求体转换成String类型第二个responseBody请求将Map对象转换成json格式输出到HTTP响应中。
RequestMapping(/requestBody)
public void requestBody(RequestBody String body, Writer writer) throws IOException{writer.write(body);
}RequestMapping(value/responseBody, producesapplication/json)
ResponseBody
public MapString, Object responseBody(){MapString, Object retMap new HashMap();retMap.put(param1, abc);return retMap;
} 这两个注解都实现了HTTP报文信息同Controller方法中对象的转换下面我们就来进行原理分析。 1、接口转换 SpringMVC中为了实现HTTP消息体和参数及返回值进行转换所有转换类都实现了HttpMessageConverter接口该接口定义了5个方法用于将HTTP请求报文转换为java对象以及将java对象转换为HTTP响应报文。
public interface HttpMessageConverterT {// 当前转换器是否能将HTTP报文转换为对象类型boolean canRead(Class? clazz, MediaType mediaType);// 当前转换器是否能将对象类型转换为HTTP报文boolean canWrite(Class? clazz, MediaType mediaType);// 转换器能支持的HTTP媒体类型ListMediaType getSupportedMediaTypes();// 转换HTTP报文为特定类型T read(Class? extends T clazz, HttpInputMessage inputMessage)throws IOException, HttpMessageNotReadableException;// 将特定类型对象转换为HTTP报文void write(T t, MediaType contentType, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException;} 对应到SpringMVC的Controller方法read方法即是读取HTTP请求转换为参数对象write方法即是将返回值对象转换为HTTP响应报文。SpringMVC定义了两个接口来操作这两个过程参数解析器HandlerMethodArgumentResolver和返回值处理器HandlerMethodReturnValueHandler。
// 参数解析器接口
public interface HandlerMethodArgumentResolver {// 解析器是否支持方法参数boolean supportsParameter(MethodParameter parameter);// 解析HTTP报文中对应的方法参数Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;}// 返回值处理器接口
public interface HandlerMethodReturnValueHandler {// 处理器是否支持返回值类型boolean supportsReturnType(MethodParameter returnType);// 将返回值解析为HTTP响应报文void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;} 参数解析器和返回值处理器在底层处理时都是通过HttpMessageConverter进行转换。流程如下 RequestResponseBodyMethodProcessor类实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler两个接口RequestBody和ResponseBody这两个注解的解析均由该类来实现。 2、参数解析 在上文中我们介绍了getMethodArgumentValues方法实现了参数解析但并未深入解析这里我们进行下源码分析 private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {MethodParameter[] parameters getMethodParameters();Object[] args new Object[parameters.length];// 遍历所有参数逐个解析for (int i 0; i parameters.length; i) {MethodParameter parameter parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);args[i] resolveProvidedArgument(parameter, providedArgs);if (args[i] ! null) {continue;} // 通过supportsParameter方法寻找参数合适的解析器if (this.argumentResolvers.supportsParameter(parameter)) {try {args[i] this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);continue;}catch (Exception ex) {if (logger.isDebugEnabled()) {logger.debug(getArgumentResolutionErrorMessage(Failed to resolve, i), ex);}throw ex;}}if (args[i] null) {throw new IllegalStateException(Could not resolve method parameter at index parameter.getParameterIndex() in parameter.getMethod().toGenericString() : getArgumentResolutionErrorMessage(No suitable resolver for, i));}}return args;} 2.1、查找解析器 HandlerMethodArgumentResolverComposite类实现了supportsParameter方法后续调用argumentResolverCache即参数解析器 private final ListHandlerMethodArgumentResolver argumentResolvers new LinkedListHandlerMethodArgumentResolver();Overridepublic boolean supportsParameter(MethodParameter parameter) {return getArgumentResolver(parameter) ! null;}private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {HandlerMethodArgumentResolver result this.argumentResolverCache.get(parameter);if (result null) {for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {if (resolver.supportsParameter(parameter)) {result resolver;this.argumentResolverCache.put(parameter, result);break;}}}return result;} 我们直接进入HandlerMethodArgumentResolver接口的实现类也正是我们上问提到的RequestResponseBodyMethodProcessor来看看 Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(RequestBody.class);} 可以看到这里实际上就是判断方法上是否有RequestBody这就印证了我们所说的RequestBody由RequestResponseBodyMethodProcessor来实现解析。 2.2、解析过程 已经通过supportsParameter确定了由RequestResponseBodyMethodProcessor类来进行解析下面再看如何解析于是我们跟着源码进入resolveArgument方法。 Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {HandlerMethodArgumentResolver resolver getArgumentResolver(parameter);if (resolver null) {throw new IllegalArgumentException(Unsupported parameter type [ parameter.getParameterType().getName() ]. supportsParameter should be called first.);}return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);} 其核心内容为通过readWithMessageConverters读取HTTP的请求体内容而该方法由AbstractMessageConverterMethodArgumentResolver负责实现。 // RequestResponseBodyMethodProcessor.javaOverridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {parameter parameter.nestedIfOptional();// 读取HTTP报文Object arg readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());String name Conventions.getVariableNameForParameter(parameter);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());}}mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX name, binder.getBindingResult());return adaptArgumentIfNecessary(arg, parameter);}Overrideprotected T Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {HttpServletRequest servletRequest webRequest.getNativeRequest(HttpServletRequest.class);ServletServerHttpRequest inputMessage new ServletServerHttpRequest(servletRequest);//调用AbstractMessageConverterMethodArgumentResolver中的实现Object arg readWithMessageConverters(inputMessage, parameter, paramType);if (arg null) {if (checkRequired(parameter)) {throw new HttpMessageNotReadableException(Required request body is missing: parameter.getMethod().toGenericString());}}return arg;} 这里的关键部分即是遍历所有的HttpMessageConverter通过canRead方法判断转换器是否支持对参数的转换然后执行read方法完成转换。
protected T Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {....try {inputMessage new EmptyBodyCheckingHttpInputMessage(inputMessage);for (HttpMessageConverter? converter : this.messageConverters) {ClassHttpMessageConverter? converterType (ClassHttpMessageConverter?) converter.getClass();....// 判断转换器是否支持参数类型if (converter.canRead(targetClass, contentType)) {if (inputMessage.getBody() ! null) {inputMessage getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);// read方法执行HTTP报文到参数的转换body ((HttpMessageConverterT) converter).read(targetClass, inputMessage);body getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);}else {body getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);}break;}...}}catch (IOException ex) {throw new HttpMessageNotReadableException(I/O error while reading input message, ex);}....return body;
} 3、返回值处理 完成Controller方法的调用后在ServletInvocableHandlerMethod的invokeAndHandle中使用返回值处理器对返回值进行转换。 这里的returnValueHandlers也是HandlerMethodReturnValueHandler的集合体HandlerMethodReturnValueHandlerComposite public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 请求处理Object returnValue invokeForRequest(webRequest, mavContainer, providedArgs);// 返回值处理this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);} 3.1、选择处理器 handleReturnValue首先会通过selectHandler找出支持处理当前返回值的处理器然后再调用该处理器的handleReturnValue方法进行真正的处理。 //HandlerMethodReturnValueHandlerComposite.javaOverridepublic void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {// 选择合适的HandlerMethodReturnValueHandler如果没有用ResposeBody注解和用了注解其返回值处理器肯定不同HandlerMethodReturnValueHandler handler selectHandler(returnValue, returnType);if (handler null) {throw new IllegalArgumentException(Unknown return value type: returnType.getParameterType().getName());}// 执行返回值处理handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);} 而selectHandler方法遍历所有HandlerMethodReturnValueHandler调用其supportsReturnType方法选择合适的HandlerMethodReturnValueHandler然后调用其handleReturnValue方法完成处理。 //HandlerMethodReturnValueHandlerComposite.javaprivate HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {boolean isAsyncValue isAsyncReturnValue(value, returnType);for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (isAsyncValue !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {continue;}// 判断当前的HandlerMethodReturnValueHandler是否支持处理返回值if (handler.supportsReturnType(returnType)) {return handler;}}return null;} RequestResponseBodyMethodProcessor要求方法上有ResponseBody注解或者方法所在的Controller类上有ResponseBody的注解。这就是常常用RestController注解代替Controller注解的原因因为RestController注解自带ResponseBody。 Overridepublic boolean supportsReturnType(MethodParameter returnType) {return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||returnType.hasMethodAnnotation(ResponseBody.class));} 3.2、处理过程 handleReturnValue方法实际也是调用HttpMessageConverter来完成转换处理 //RequestResponseBodyMethodProcessor.javaOverridepublic void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage createInputMessage(webRequest);ServletServerHttpResponse outputMessage createOutputMessage(webRequest);// 调用HttpMessageConverter执行writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);} AbstractMessageConverterMethodProcessor使用canWrite方法选择合适的HttpMessageConverter然后调用write方法完成转换。
//AbstractMessageConverterMethodProcessor.java
protected T void writeWithMessageConverters(T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {....if (selectedMediaType ! null) {selectedMediaType selectedMediaType.removeQualityValue();for (HttpMessageConverter? messageConverter : this.messageConverters) {// 判断是否支持返回值类型返回值类型很有可能不同如StringMapList等if (messageConverter.canWrite(valueType, selectedMediaType)) {outputValue (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,(Class? extends HttpMessageConverter?) messageConverter.getClass(),inputMessage, outputMessage);if (outputValue ! null) {addContentDispositionHeader(inputMessage, outputMessage);// 执行返回值转换((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);...}return;}}}....
} 补充 上文中提到的解析器和转换器都是在适配器初始化的时候添加的。 //RequestMappingHandlerAdapter.javapublic RequestMappingHandlerAdapter() {StringHttpMessageConverter stringHttpMessageConverter new StringHttpMessageConverter();stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316this.messageConverters new ArrayListHttpMessageConverter?(4);this.messageConverters.add(new ByteArrayHttpMessageConverter());this.messageConverters.add(stringHttpMessageConverter);this.messageConverters.add(new SourceHttpMessageConverterSource());this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());}Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers null) {ListHandlerMethodArgumentResolver resolvers getDefaultArgumentResolvers();this.argumentResolvers new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers null) {ListHandlerMethodArgumentResolver resolvers getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers null) {ListHandlerMethodReturnValueHandler handlers getDefaultReturnValueHandlers();this.returnValueHandlers new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}