网站如何做微信支付宝支付宝支付,网页传奇发布网,鄂尔多斯网站建设公司,公司做网站需要哪些内容其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录
其他系列文章导航
文章目录
前言
一、BUG详情
1.1 报错信息 1.2 接口响应信息
1.3 全局异常处理器的定义
二、排查过程
三、解决方案
四、总结 前言
最近… 其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录
其他系列文章导航
文章目录
前言
一、BUG详情
1.1 报错信息 1.2 接口响应信息
1.3 全局异常处理器的定义
二、排查过程
三、解决方案
四、总结 前言
最近在开发过程中我遇到一个不易察觉的小bug。这个bug并没有直接给出报错信息使得排查问题的根源变得困难。我希望通过分享这个经验帮助大家避免重蹈覆辙以免浪费不必要的时间和精力。
为了避免类似的困境我们应当时刻保持警惕对开发过程中的每一个细节都进行严格的检查。同时利用调试工具和日志输出等功能可以帮助我们更快速地定位和解决问题。此外定期进行代码审查和测试也是非常必要的这有助于发现潜在的问题并及时解决。 一、BUG详情
1.1 报错信息
如下图所示
java.lang.reflect.UndeclaredThrowableException: null
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:780) ~[spring-aop-5.3.27.jar:5.3.27]
Caused by: exception.NoAuthorityException: 无权限访问 1.2 接口响应信息 预期是抛出无权限访问异常但是没有被aop捕获被上层UndeclaredThrowableException异常捕获。 1.3 全局异常处理器的定义
如下图所示
ExceptionHandler(Exception.class)public T RT handle(Exception exception) {if (exception instanceof BindException) {// Bind错误特殊处理return R.wrap(() - {ApiValidationUtil.checkBinding(((BindException) exception).getBindingResult());return null;});}return R.errorAndLog(exception);} 二、排查过程
找到最上面一层报错发现错误在CglibAopProxy.class中。
附上源码逻辑 OverrideNullablepublic Object proceed() throws Throwable {try {return super.proceed();}catch (RuntimeException ex) {throw ex;}catch (Exception ex) {if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {// Propagate original exception if declared on the target method// (with callers expecting it). Always propagate it for Kotlin code// since checked exceptions do not have to be explicitly declared there.throw ex;}else {// Checked exception thrown in the interceptor but not declared on the// target method signature - apply an UndeclaredThrowableException,// aligned with standard JDK dynamic proxy behavior.throw new UndeclaredThrowableException(ex);}}}
从源码可以看出咱们最后抛出的异常就是UndeclaredThrowableException异常所以说if块里面的逻辑是false。
继续深挖ReflectionUtils.declaresException(getMethod(), ex.getClass())方法的逻辑。
附上declaresException方法源码
public static boolean declaresException(Method method, Class? exceptionType) {Assert.notNull(method, Method must not be null);Class?[] declaredExceptions method.getExceptionTypes();for (Class? declaredException : declaredExceptions) {if (declaredException.isAssignableFrom(exceptionType)) {return true;}}return false;}method就是方法体了exceptionType就是异常类型了。
method.getExceptionTypes()从controller层读到异常类型存入declaredExceptions中与传入的exceptionType进行判断。
declaredException.isAssignableFrom(exceptionType)的意思是declaredException是不是exceptionType的父类。只要满足捕获的异常是接口抛出异常的父类就行了。
因为原来的controller层接口是并没有声明异常。
如下所示 //原先的接口Role(400)Overridepublic RUserInfoVO getUserInfo(String loginName) {Assert.notNull(loginName, 请求参数为空);return sysUserInfoService.getUserInfo(loginName);}所以declaredExceptions是空的那当然返回的是false。
所以走了else的逻辑向上抛出throw new UndeclaredThrowableException(ex)。 三、解决方案
在接口方法上声明错误类型exceptionType。
如下所示 Role(400)Overridepublic RUserInfoVO getUserInfo(String loginName) throws NoAuthorityException {Assert.notNull(loginName, 请求参数为空);return sysUserInfoService.getUserInfo(loginName);}
这样的话Class?[] declaredExceptions method.getExceptionTypes();可以读到NoAuthorityException 异常并和拦截到的异常ex.getClass()得到也是NoAuthorityException异常做对比满足isAssignableFrom方法所以成功捕获。
由此可见我们把ex.getClass()也就是AOP里要捕获的异常设置为Exception也是可以满足需求的。
附一张成功响应图 四、总结
在本次博客中我们讨论了AOP跨模块捕获异常时CGLIB拦截导致异常继续向上抛出的问题。通过分析问题原因和解决方案我们了解到CGLIB拦截异常是由于代理对象与目标对象继承关系导致的问题。通过使用AspectJ的解决方案我们可以避免该问题的发生从而更好地实现AOP功能。
通过分析CGLIB拦截异常的原因和提出解决方案我们更好地了解了AOP的实现方式和如何解决跨模块异常处理的问题。这对于在实际开发中更好地应用AOP技术具有重要的指导意义。