线上问题
近期在线上系统中遇到了一个奇怪的问题,某个请求处理失败了,但是日志里没有任何错误信息,catch(Exception e) {}
代码块根本没有执行,因此直接跳过了错误处理逻辑,但是finally{}
块却执行了。根据此现象我们推测出很可能是代码块抛出了非Exception
子类的异常。果然,将catch Exception
改为catch Throwable
后, 日志中出现了java.lang.IncompatibleClassChangeError
异常。因为此异常是Error
而不是Exception
的子类,所以导致了出现catch{}
没有执行但finally
执行了的现象。
关于Exception
在很多入门书上都会有类似于"Exception是可恢复的而Error往往是不可恢复的系统严重错误"这样的内容,当然,这句话本身是没问题的,问题在于即便是Error错误我们也应该捕获一下,至少要记一下日志,如果忽略掉的话就会出现上面这种莫名其妙失败但又找不到线索的情况。
经查,报
java.lang.IncompatibleClassChangeError
的原因是最近一次上线时引入了新的业务jar包,此依赖的某个传递依赖版本跟原有系统中的jar版本有冲突,导致JVM在执行时报错。这个问题之所以在测试时没有发现,还有一个原因,就是只有在执行到特定逻辑时才会触发,并不是每次都会出现,非常隐蔽。
如果偶尔看过Netty的代码,你会发现Netty所有的catch, 最后都是以catch(Throwable e)
结尾的,而不是Exception
。我们在编码时也应该以catch Throwable
兜底, 不要再使用Exception
了。