大幕拉开
接下来,神奇的事情就要发生了,铁子。
com.example.transactional.exception.AgeExceptionOver18
com.example.transactional.exception.AgeException
虽然这是两个不同的异常,但是这两个字符串进行 contains 操作,你说是不是返回 true?
但是,如果下面这两个字符串进行 equals 操作,你说是不是返回 false,问题就得到解决了?
com.example.transactional.exception.AgeExceptionOver18
com.example.transactional.exception.AgeException
道理是这么个道理,但是我觉得问题肯定没这么简单。
首先我觉得这里用 contains 肯定是故意的,但是具体出于什么目的,我还真不确定。
于是和我讨论的读者提出一个看法,会不会是为了满足 rollbackForClassName 这个属性:
在正常使用的场景下,我们是可以完成回滚操作的。
对应地方的代码的值是这样的;
java.lang.NullPointerException 字符串当然包含了 NullPointerException 字符串。所以我们进行回滚嘛。没毛病。
但是如果我们用 equals 操作,那么就匹配不上,导致 rollbackForClassName 属性失效了。
所以把 contains 修改为 equals 属于拆西墙,补东墙的措施,不可取。
但是 rollbackForClassName 属性在我们的 Demo 下,也是没有效果的。
比如我把程序改成这样,你说,是不是就乱套了?
同样的道理嘛。
com.example.transactional.exception.AgeExceptionOver18 字符串当然包含了 AgeException 字符串了。
但是我并不想回滚啊,哥,你好好看看,我抛出来的异常是 AgeExceptionOver18 呀。
到这里,我想问题我应该已经描述的非常清楚了,要是你还是没明白问题是什么,那你不用往下看了,再看一下“大幕拉开”这一节。
不然后面你很难入戏。
铺垫一波
为了把真正的问题更好的抛出来,我必须得先把另外一个相关的问题引出来,作为铺垫。
首先,我们去 Spring 项目的 issues 里面搜一下 getDepth 方法所在的 RollbackRuleAttribute 这个类。
看看有没有相关的蛛丝马迹,结果如下:
经过分析,对我有帮助的也只有第一条内容。
https://github.com/spring-projects/spring-framework/pull/24682
题目叫做:
Improve javadoc in RollbackRuleAttribute regarding nested classes。
改进 RollbackRuleAttribute 中关于嵌套类的 javadoc。
从题目我们知道这是一次对于文档的改进。
那么具体是啥改进呢?
可以看到他的描述中也提到了我们前面分析的那一个“万恶之源”的方法。
关于他具体说了什么,其实我也不用给你翻译,直接给你看他提交的代码就一目了然了:
他主要说个了内部类的问题,而且他这个问题和我们的还有点不一样。
他的两个异常类,一个叫 EnclosingException,另一个叫做 EnclosedException,这两个字符串是不存在 contains 关系的。
那么在内部类的场景下,问题是什么呢?
我也给你演示一个,你只需要看一眼就明白了,示例代码如下:
需要注意的是,我现在的两个异常是 AgeException 和 AgeOver18Exception,这二者并不存在包含关系。
前面做 Demo 的时候是 AgeExceptionOver18。
AgeOver18Exception
AgeExceptionOver18
别看花眼了。
你看,内部类的时候抛出异常是这样的:
throw new AgeException.AgeOver18Exception();
你要是没回过味儿来,没关系,断点一打,代码一跑就恍然大悟:
看明白没,铁子。内部类抛出的异常的全路径名称是这样的:
xxx.UserInfoService\$ AgeException$AgeOver18Exception
这不就包含 AgeException 了吗,不就匹配上了吗,不就回滚了吗?
所以,虽然他这个问题的触发方式和我前面提到的还不一样,但是“万恶之源”是一样的。
那么解决方案是什么呢?
仅仅是修改了一下文档,从文档的角度表明了这个情况是会被回滚的:
对应到源码,也就是这个地方的注释:
org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(java.lang.Class<?>)
好,我们现在冷静的思考一下,这里仅仅是从文档的角度来修复这个问题,在文档里面明确说明指定异常的内部类也会被回滚,这个做法对不对?
我认为勉强是可以接受的。
比如,我们知道某个异常类被标记为应该被回滚,那么这个异常类的子类应该被回滚,这是没问题的。
我认为内部类和子类应该保存同样的逻辑,毕竟它们之前确实存在代码上的关联关系,从这个角度上也说的过去。
毕竟一切解释权归官方所有嘛。
到这里你要记住:
- RollbackRuleAttribute 类已经因为在回滚异常的判断上使用 contains 爆出过内部类的问题。
- 这个问题通过修改 javadoc 描述的方式进行了修复,没有修改任何代码。
- 这个解决方案勉强说的过去。
好了,铺垫完成了。