开发日志02-解决`response`和SpringAop层相关冲突报错问题

打印 上一主题 下一主题

主题 545|帖子 545|积分 1635

解决一个Bug

在昨晚的开发中遇到了一个非常令人头疼的Bug
java.lang.IllegalStateException: getOutputStream() has already been called for this response
报错信息如下:有点长。。。
  1. java.lang.IllegalStateException: getOutputStream() has already been called for this response
  2.         at org.apache.catalina.connector.Response.getWriter(Response.java:584)
  3.         at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:227)
  4.         at com.alibaba.fastjson.serializer.ASMSerializer_2_ResponseFacade.write(Unknown Source)
  5.         at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:333)
  6.         at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:311)
  7.         at com.alibaba.fastjson.serializer.ObjectArrayCodec.write(ObjectArrayCodec.java:118)
  8.         at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:285)
  9.         at com.alibaba.fastjson.JSON.toJSONString(JSON.java:745)
  10.         at com.alibaba.fastjson.JSON.toJSONString(JSON.java:683)
  11.         at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648)
  12.         at com.sirc.modelservice.aop.ControllerAspect.logBeforeController(ControllerAspect.java:45)
  13.         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  14.         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  15.         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  16.         at java.lang.reflect.Method.invoke(Method.java:497)
  17.         at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
  18.         at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:617)
  19.         at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:44)
  20.         at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:57)
  21.         at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
  22.         at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
  23.         at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
  24.         at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
  25.         at
  26.     ............
复制代码
一开始是认为自己写的关于IO流的代码资源忘记关闭
自己检查两遍后确认没有问题
进入Debug模式
发现被调用接口根本就进不了对应方法
再次观察错误信息
  1. #                at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648)
  2. ......
  3. #                at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
  4. .......
  5. #                        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
复制代码
大概猜到是fastJson包和SpringAop切面那里出了问题
果然,经过百度过后
发现fastjson内的方法使用了类似于out.write()等方法
  1. //部分代码        
  2. for(int var10 = 0; var10 < var9; ++var10) {
  3.             SerializeFilter filter = var8[var10];
  4.             serializer.addFilter(filter);
  5.         }
  6.     }
  7. //this
  8.     serializer.write(object);
  9.     var15 = out.toString();
  10. } finally {
  11.     out.close();
  12. }
复制代码
这个和JSP中调用的response.getOutputStream()产生冲突.
即Servlet规范说明

不能既调用response.getOutputStream(),又调用response.getWriter(),
于是就着手解决方案,因为团队技术文档 需要这个切面来记录每次请求前的信息以及请求后的返回信息,并保存在日志中。
于是我就在想能不能在切面原本匹配的方法中,排除某一个方法
解决方案
  1.     @Pointcut("execution(public * x.x.x.controller.*.*(..))")
  2.     public void commonController(){}
  3.     @Pointcut("execution(public * x.x.x.controller.SqlController.export(..))")
  4.     public void excludeController() {
  5.     }
  6.     @Pointcut("commonController() && !excludeController()")
  7.     public void allPointcutWeb() {
  8.     }
复制代码
在定义切面的时候 单独匹配出需要排除的方法
并使用
  1. @Pointcut("commonController() && !excludeController()")
复制代码
排除该方法
--最后

该操作要根据实际需求,本次需求的请求不携带任何信息,所以不需要环绕通知也可以。
如果你的方法确实需要环绕通知的话,可以尝试使用
ResponseEntity
-------谢谢 v

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表