在Java中UndeclaredThrowableException是Java反射机制中使用的一个特殊异常类,通常与InvocationHandler接口一起使用,在通过反射调用方法时,如果方法声明抛出了受检查异常(checked exception),但是在方法上并没有声明抛出的这些异常,那么就会抛出UndeclaredThrowableException异常。这个异常包装了实际发生的受检异常,使其可以作为一个非受检异常(unchecked exception)被抛出。
UndeclaredThrowableException继承自RuntimeException,并且它有一个getUndeclaredThrowable()方法,用户获取被包装的原始受检异常。
一、抛出受检异常未在方法上声明
@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();if (method.isAnnotationPresent(RateLimiter.class)) {RateLimiter rateLimiter = method.getAnnotation(RateLimiter.class);// 解析key,替换变量String key = resolveKey(invocation, rateLimiter.key());// 获取已访问次数int count = getVisitedTimes(key);// 获取最大访问次数int maxPermits = rateLimiter.maxPermits();if (count >= maxPermits) {throw new IllegalAccessException(rateLimiter.message());}// 当前访问次数+1addVisitedTimes(key, rateLimiter);}return invocation.proceed();}
上述代码会抛出IllegalAccessException异常,但是没有在方法的throws中声明抛出,这是IllegalAccessException异常就会被UndeclaredThrowableException异常包装。
二、将受检异常包装成UndeclaredThrowableException异常
@Nullablepublic Object proceed() throws Throwable {try {return super.proceed();} catch (RuntimeException var2) {RuntimeException ex = var2;throw ex;} catch (Exception var3) {Exception ex = var3;if (!ReflectionUtils.declaresException(this.getMethod(), ex.getClass()) && !KotlinDetector.isKotlinType(this.getMethod().getDeclaringClass())) {throw new UndeclaredThrowableException(ex);} else {throw ex;}}}
在org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed方法中对受检异常进行包装。
三、如何获取真实的异常信息
- 全局异常处理时通过getUndeclaredThrowable()方法处理
@ResponseBody@ResponseStatus(HttpStatus.OK)@ExceptionHandler(UndeclaredThrowableException.class)public Object undeclaredThrowableException(UndeclaredThrowableException e, HttpServletRequest request, HandlerMethod handlerMethod) {recordErrorMsg(e, request);Throwable throwable = e.getUndeclaredThrowable();if (throwable != null) {return getApiResponseWrapper(handlerMethod, AppStatusType.ILLEGAL_PROXY.getStatus(), throwable.getMessage());}return getApiResponseWrapper(handlerMethod, AppStatusType.ILLEGAL_PROXY);}
通过UndeclaredThrowableException异常的getUndeclaredThrowable()方法获取真实的受检查异常,获取异常信息抛出。
- 在方法上声明受检查异常
- 在方法中直接通过try catch方法捕获异常并处理成期望的结果;
开源SDK:https://github.com/mingyang66/spring-parent