接口标记为@ResponseBody却不进入ResponseBodyAdvice
一、背景:
我们的接口为了统一,在ResponseBodyAdvice中对返回值做统一处理,默认添加了errorNo和errorInfo字段返回。
最近同事改接口代码的时候,发现接口返回值是空的。乍一看,没什么重大修改。
接口代码大致就是下面这个样子:
@ResponseBody
@RequestMapping("test")
public void test(HttpServletRequest request, HttpServletResponse response){
// 业务逻辑处理
}
二、问题分析
顺着这个接口,单步调试跟到Spring的源码ServletInvocableHandlerMethod#invokeAndHandle方法
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()) {
mavContainer.setRequestHandled(true);
// 直接进入到这里就return出去了
return;
}
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
// 要进到这里才会进入到ResponseBodyAdvice中
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
再对着源码,看下return出去的4个条件,核对一下我们的接口
void类型,返回值确实是null
isRequestNotModified(webRequest) ,false
getResponseStatus() != null ,false
如果在test方法上标记@ResponseStatus(HttpStatus.OK),这里取到的就不是null
mavContainer.isRequestHandled(),true
那么问题来了,mavContainer.isRequestHandled()=true是什么时候设置的呢?
重新debug,发现在ServletResponseMethodArgumentResolver#resolveArgument中设置的,源码截取如下:
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
if (mavContainer != null) {
// 就是这里设置的了
mavContainer.setRequestHandled(true);
}
// 略 ...
}
三、问题小结
通过上面的分析,问题已经明朗了。
- 接口一直都是返回null的。开发此次修改的时候,在接口入参里面加了HttpServletResponse
- 因为有HttpServletResponse入参,就会进入到ServletResponseMethodArgumentResolver
- 因为ModelAndViewContainer不为null,mavContainer.setRequestHandled(true);
- 满足前面ServletInvocableHandlerMethod#invokeAndHandle的条件,直接return
- 返回空结果
接口标记为@ResponseBody却不进入ResponseBodyAdvice的更多相关文章
- 接口没添加@responseBody注解
今天在重写springaop小demo时,发现调用接口时,可以在控制台上正常返回结果,但是页面报错,debug半天,可以看到是调用了modelview的时候出错,找不到视图了.. debug的时候控制 ...
- 为什么这些java接口没有抽象方法?浅谈Java标记接口
在jdk的源码中,存在这样的一些接口,他们不包含任何的(抽象)方法,但是却广泛的存在. 这种接口我们称之为Mark Interface,也就是标记接口. 这些接口呢,我们不用来实现任何的方法,他们的作 ...
- 内功心法 -- Java标记接口
写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...
- Java 标记接口
没有声明或定义方法的接口称为标记接口(Mark Interface).某个类实现该接口时不需要重写方法,表明具有接口标记的功能.Java中常用的3个标记接口如下: 1 Serializable jav ...
- Java的四个标记接口:Serializable、Cloneable、RandomAccess和Remote接口
一.概述 标记接口是一些没有属性和方法的接口,也是一种设计思想.Java中的一个标记接口表示的的是一种类的特性,实现了该标记接口的类则具有该特性.如实现了Serializable接口的类,表示这个类的 ...
- Java标记接口
写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...
- java接口调用——webservice就是一个RPC而已
很多新手一听到接口就蒙逼,不知道接口是什么!其实接口就是RPC,通过远程访问别的程序提供的方法,然后获得该方法执行的接口,而不需要在本地执行该方法.就是本地方法调用的升级版而已,我明天会上一篇如何通过 ...
- IGS_学习笔记05_IREP开发Concurrent Program为客户化集合接口(案例)
20150819 Created By BaoXinjian
- 利用Swagger2自动生成对外接口的文档
一直以来做对外的接口文档都比较原始,基本上都是手写的文档传来传去,最近发现了一个新玩具,可以在接口上省去不少麻烦. swagger是一款方便展示的API文档框架.它可以将接口的类型最全面的展示给对方开 ...
随机推荐
- 【00NOIP普及组】税收与补贴问题(信息学奥赛一本通 1911)( 洛谷 1023)
[题目描述] 每样商品的价格越低,其销量就会相应增大.现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给 定的最高价位后,销量以某固定 ...
- 【转】使用eclipse的todo标签管理任务
Eclipse中的一些特殊的注释技术包括: 1. // TODO —— 表示尚未完成的待办事项. 2. // XXX —— 表示被注释的代码虽然实现了功能,但是实现方案有待商榷 ...
- AnonymousPipeStream的使用案例
AnonymousPipeStream的使用具体案例如下: 服务端: using System; using System.Data; using System.Data.SQLite; using ...
- EMQ 与 mqtt 与 IOT设备
1.IOT设备的特性 IOT(物联网things of internet)设备和传统的智能设备有什么区别,笔者总结下的IOT设备有如下特点: 硬件能力差(存储能力基本只有几MB,CPU频率低连使用HT ...
- kafka发送超大消息设置
最近开发一cdc框架,为了测试极端情况,需要kafka传递100万条数据过去,1个G左右,由于其他环节限制,不便进行拆包(注:测下来,大包走kafka不一定性能更好,甚至可能更低). 测试百万以上的变 ...
- (十三)GBDT模型用于评分卡模型python实现
python信用评分卡建模(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_ca ...
- win 10 关闭或打开 测试模式
一.关闭测试模式 方法: 以管理员身份运行 cmd 运行:bcdedit /set testsigning off 重启电脑 二.开启测试模式 以管理员身份运行 cmd 运行:bcdedit /set ...
- Oracle系列八 高级子查询
子查询 子查询 (内查询) 在主查询执行之前执行 主查询(外查询)使用子查询的结果 多列子查询 主查询与子查询返回的多个列进行比较 多列子查询中的比较分为两种: 成对比较 问题:查询与141号或174 ...
- JMeter 使用 http长连接的方法
前言 如果需要在JMeter通过http长连接发送请求,首先需要选择了Use KeepAlive 长连接协议,虽然默认是勾选的,但也需要确认一下. 除了选择了Use KeepAlive 长连接协议,还 ...
- [LeetCode] 204. Count Primes 计数质数
Description: Count the number of prime numbers less than a non-negative number, n click to show more ...