spring注解@ResponseBody
来源:互联网 发布:mac pro 15寸 携带 编辑:程序博客网 时间:2024/05/04 17:14
今天工作的时候,一不小心就对spring如何通过注解来解析请求好奇了。
查询了资料,spring mvc请求处理大致是这样子的,由DispatcherServlet截获请求,DispatcherServlet通过handlerMappng得到HandlerExecutionChain。然后获得HandlerAdapter。
HandlerAdapter内部对于每个请求生成一个ServletInvocableHandlerMethod进行处理。而ServletInvocableHandlerMethod处理时会分成请求和响应两部分进行。然后ServletInvocableHandlerMethod得到ModelAndView进行处理。
1. 处理请求的时候,会根据ServletInvocableHandlerMethod的属性argumentResolvers(这个属性是它的父类InvocableHandlerMethod中定义的)进行处理,其中argumentResolvers属性是一个HandlerMethodArgumentResolverComposite类(这里使用了组合模式的一种变形),这个类是实现了HandlerMethodArgumentResolver接口的类,里面有各种实现了HandlerMethodArgumentResolver的List集合。
- 处理响应的时候,会根据ServletInvocableHandlerMethod的属性returnValueHandlers(自身属性)进行处理,returnValueHandlers属性是一个HandlerMethodReturnValueHandlerComposite类(这里使用了组合模式的一种变形),这个类是实现了HandlerMethodReturnValueHandler接口的类,里面有各种实现了HandlerMethodReturnValueHandler的List集合。
ServletInvocableHandlerMethod的returnValueHandlers和argumentResolvers这两个属性都是在ServletInvocableHandlerMethod进行实例化的时候被赋值的(使用RequestMappingHandlerAdapter的属性进行赋值)。
RequestMappingHandlerAdapter的argumentResolvers和returnValueHandlers这两个属性是在RequestMappingHandlerAdapter进行实例化的时候被Spring容器注入的。
其中默认的ArgumentResolvers:
默认的returnValueHandlers:
使用@ResponseBody注解的话最终返回值会被RequestResponseBodyMethodProcessor这个HandlerMethodReturnValueHandler实现类处理。
我们通过源码发现,RequestResponseBodyMethodProcessor这个类其实同时实现了HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver这两个接口。
RequestResponseBodyMethodProcessor支持的请求类型是Controller方法参数中带有@RequestBody注解,支持的响应类型是Controller方法带有@ResponseBody注解。
RequestResponseBodyMethodProcessor响应的具体处理是使用消息转换器。
处理请求的时候使用内部的readWithMessageConverters方法。
然后会执行父类(AbstractMessageConverterMethodArgumentResolver)的readWithMessageConverters方法。
“`java
protected Object readWithMessageConverters(NativeWebRequest webRequest,
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest); InputStream inputStream = inputMessage.getBody(); if (inputStream == null) { return handleEmptyBody(methodParam); } else if (inputStream.markSupported()) { inputStream.mark(1); if (inputStream.read() == -1) { return handleEmptyBody(methodParam); } inputStream.reset(); } else { final PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream); int b = pushbackInputStream.read(); //如果返回的值是空的 if (b == -1) { //检查有没有Responsebody注解,有抛出一个异常 return handleEmptyBody(methodParam); } else { pushbackInputStream.unread(b); } inputMessage = new ServletServerHttpRequest(servletRequest) { @Override public InputStream getBody() throws IOException { // Form POST should not get here return pushbackInputStream; } }; }
//有数据,则调用父类的方法
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
}
java
父类的方法readWithMessageConverters,通过对应的media的类型调用HttpMessageConverter方法,遍历并且使用了Read方法。
protected Object readWithMessageConverters(HttpInputMessage inputMessage,
MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {
MediaType contentType; try { contentType = inputMessage.getHeaders().getContentType(); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { contentType = MediaType.APPLICATION_OCTET_STREAM; } Class<?> contextClass = methodParam.getContainingClass(); for (HttpMessageConverter<?> converter : this.messageConverters) { if (converter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter; if (genericConverter.canRead(targetType, contextClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + targetType + "] as \"" + contentType + "\" using [" + converter + "]"); } return genericConverter.read(targetType, contextClass, inputMessage); } } Class<T> targetClass = (Class<T>) ResolvableType.forMethodParameter(methodParam, targetType).resolve(Object.class); if (converter.canRead(targetClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + targetClass.getName() + "] as \"" + contentType + "\" using [" + converter + "]"); } return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage); } } throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);}
“`
- Spring注解@ResponseBody
- spring注解@ResponseBody
- Spring 注解 @ResponseBody
- Spring注解:@Responsebody与@RequestBody
- Spring 注解@ResponseBody,@RequestBody,@PathVariable
- Spring MVC注解之@ResponseBody
- 【spring注解解析】@RequestBody,@ResponseBody
- Spring 注解 @Responsebody与@RequestBody
- Spring注解@ResponseBody中文乱码
- Spring 注解学习 @ResponseBody,@RequestBody,@PathVariable
- spring MVC 注解处理分析(一) @ResponseBody
- Spring MVC 利用 @ResponseBody 注解返回JSON
- spring注解@ResponseBody处理ajax请求
- Spring 注解的使用 @ResponseBody,@RequestBody
- Spring Mvc中Controller 中的@ResponseBody 注解
- Spring中Responsebody注解的作用
- Spring 注解学习@ResponseBody,@RequestBody,@PathVariable
- Spring 注解 @responsebody 的优势与劣势
- [codeforces] C - Pythagorean Triples 数学
- 创建型模式之工厂方法模式
- 一般处理程序返回的json数据,前台接收不到问题
- Android之UI界面--软键盘弹起至登陆按钮下方
- 从零开始自动部署Django项目(四): 在Docker中部署Django项目
- spring注解@ResponseBody
- [LeetCode]--234. Palindrome Linked List
- windows下面安装安装redis和redis扩展
- java网络编程Socket单服务器与多客户端
- 递推3
- 图片悬停显示大图效果
- 伸展树(Splay Tree)
- 调整虚拟机中Ubuntu Server 屏幕分辨率
- 23种设计模式全解析