文章目录
- 一、异常分类
- 二、throw、throws、try-catch-finally
- 三、CglibAopProxy中对异常的处理
- 4、关于UndeclaredThrowableException
一、异常分类
java异常层级结构
- Throwable:所有异常的根接口
- Error:严重错误,程序无法处理和恢复
- 例如VirtualMachineError,OOMError等
- Exception:异常,程序可以捕获并可能恢复
- RuntimeException: 运行时异常,无需强制捕获
- NullPointerException
- ClassCastException
- ArithmeticException
- IllegalArgumentException
- IOException: IO操作异常
- FileNotFoundException
- SocketException
- SQLException: SQL数据库访问异常
- TimeoutException: 超时异常
- ParseException: 解析错误异常
- OtherException: 其他领域特定的异常
- HttpException
- ASFException
- 自定义Exception:用户自定义的业务异常
从另一个角度看java异常分为Checked Exception和Unchecked Exception
- Checked Exception: 需要捕获或者声明抛出的异常,如果没有处理则不能编译通过。主要包括Exception及其子类,不包括RuntimeException。例如IOException、SQLException等。
- Unchecked Exception: 不需要强制捕获的异常,可以不处理。主要包括RuntimeException及其子类。例如NullPointerException、ClassCastException等
Checked Exception举例:
public class Test{
public static void main(String[] args) throws IllegalAccessException {
int a = new Random().nextInt(10);
System.out.println(a);
if(a % 2 == 1){
throw new IllegalAccessException("This is an checked exception.");
}
}
}
这里如果不声明(throws)或捕获(try-catch)异常编译会报错
加上throws IllegalAccessException编译通过,运行结果如下
Unchecked Exception举例:
public class Test {
public static void main(String[] args){
int a = new Random().nextInt(10);
System.out.println(a);
if(a % 2 == 1){
throw new IllegalArgumentException("This is an unchecked exception.");
}
}
}
这里没有throws或try-catch编译通过
运行结果如下
ps::注意上面例子上两种异常(IllegalAccessException和IllegalArgumentException),不要看错了
二、throw、throws、try-catch-finally
- throw: 用于抛出一个异常对象,通常在方法体内使用。
例如:
throw new IOException("文件读取错误");
- throws: 声明一个方法可能抛出的异常类型,出现在方法签名中。
例如:
public void readFile(String file) throws IOException {
// 方法实现
}
- try-catch-finally: 用于捕获异常,try代码块表示需要捕获异常的代码,catch表示捕获到异常后的处理逻辑,finally表示需要额外处理的逻辑
finally中的内容是一定会执行的,无论有没有捕获异常。常用于关闭IO流等做一些收尾操作。
例如:
try {
readFile(file);
} catch (IOException e) {
// 处理IO异常
} finally {
// 额外逻辑
}
三、CglibAopProxy中对异常的处理
在CglibAopProxy中有一个内部类CglibMethodInvocation,而CglibMethodInvocation中的proceed()方法对捕获的异常做了一个逻辑处理
@Nullable
public Object proceed() throws Throwable {
try {
return super.proceed();
} catch (RuntimeException var2) {
// RuntimeException或其子类直接抛出 ---- 1
throw var2;
} catch (Exception var3) {
// 非RunTimeException需根据Cglib代理的方法抛出的异常判断 ---- 2
// 是代理方法抛出的异常或该异常的子类则 ---- 3
// 若不是则抛出UndeclaredThrowableException异常 ---- 4
if (!ReflectionUtils.declaresException(this.getMethod(), var3.getClass()) && !KotlinDetector.isKotlinType(this.getMethod().getDeclaringClass())) {
throw new UndeclaredThrowableException(var3);
} else {
throw var3;
}
}
}
上述代码2、3、4实现主要由if语句条件中ReflectionUtils.declaresException()方法实现
方法参数:
Method method
:代理的方法
Class<?> exceptionType
:抛出的异常(不是代理方法抛出的),这里是aop中抛出的IllegalAccessException
public static boolean declaresException(Method method, Class<?> exceptionType) {
Assert.notNull(method, "Method must not be null");
// 获取代理方法中抛出的异常类型
Class<?>[] declaredExceptions = method.getExceptionTypes();
Class[] var3 = declaredExceptions;
int var4 = declaredExceptions.length;
// 判断捕获的异常是否是代理方法抛出的异常或该异常子类
for(int var5 = 0; var5 < var4; ++var5) {
Class<?> declaredException = var3[var5];
if (declaredException.isAssignableFrom(exceptionType)) {
return true;
}
}
return false;
}
举例说明:
这里自定义注解+aop切面增强某个controller方法时抛出了IllegalAccessException异常
controller中并未throws任何异常
运行结果
返回给前端的结果也是这个,并没有返回我们写的IllegalAccessException
打断点调试
先走到CglibAopProxy这
因为IllegalAccessException不是RuntimeException的子类,所以走到了if条件语句这
进入到ReflectionUtils.declaresException()方法
查看控制台debug的内容可知他从method中获取的异常类型
可见是没有获取到任何异常的,因为上面controller中并未手动抛出任何异常
所以最后ReflectionUtils.declaresException(this.getMethod(), var3.getClass())
返回的结果是false
抛出UndeclaredThrowableException异常
看名字能知道这个异常的意思是未声明的异常
4、关于UndeclaredThrowableException
一文搞懂 UndeclaredThrowableException