当使用 JDK 动态代理时,如果目标方法抛出一个未在代理接口上声明的异常时,会发生 UndeclaredThrowableException
异常。这个异常用于包装仅在运行时可知的受检查异常或 “错误”(Error)类型的异常(例如 java.io.IOException
或 java.lang.OutOfMemoryError
),从而响应于在虚拟机集线器(InvocationHandler)中调用目标方法的异常。下面给出详细的攻略:
JDK中动态代理异常处理分析:UndeclaredThrowableException
当我们使用 JDK 动态代理进行方法调用时,如果目标方法抛出一个未在代理接口上声明的异常,就会发生 UndeclaredThrowableException
异常,如下所示:
interface Foo {
void foo() throws Exception;
}
class FooImpl implements Foo {
public void foo() throws Exception {
throw new Exception();
}
}
class Main {
public static void main(String[] args) {
Handler handler = new Handler(new FooImpl());
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
try {
foo.foo();
} catch (UndeclaredThrowableException e) {
System.out.println(e.getCause());
}
}
}
class Handler implements InvocationHandler {
private final Object target;
public Handler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}
输出结果是:java.lang.Exception
。
JDK 动态代理在执行方法调用时,是通过 InvocationHandler#invoke
方法进行拦截并进行处理的,但是 method.invoke()
抛出的异常类型只有两种:受检查异常和未经检查的异常。受检查异常需要在接口中声明,而未经检查的异常则不需要。我们可以通过在调用 invoke
方法时设置异常处理程序来处理受检查异常和未经检查的异常。
如果目标方法抛出一个未在代理接口上声明的受检查异常,那么运行时系统将使用 UndeclaredThrowableException
异常,该异常的 getCause()
方法返回由 method.invoke()
抛出的实际异常。
例如,如果上面的 Foo
接口从 Exception
中继承 Throwable
,那么上面的代码将打印 java.lang.Exception
,而不是 UndeclaredThrowableException
。
下面再给出一个例子:
interface Bar {
void bar() throws Exception;
}
class BarImpl implements Bar {
public void bar() {
throw new RuntimeException();
}
}
class Main {
public static void main(String[] args) {
Handler handler = new Handler(new BarImpl());
Bar bar = (Bar) Proxy.newProxyInstance(Bar.class.getClassLoader(), new Class<?>[] { Bar.class }, handler);
try {
bar.bar();
} catch (UndeclaredThrowableException e) {
System.out.println(e.getCause());
}
}
}
class Handler implements InvocationHandler {
private final Object target;
public Handler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(target, args);
} catch (UndeclaredThrowableException e) {
throw e.getCause();
}
}
}
在这个例子中,BarImpl#bar()
抛出一个未经检查的异常。由于未经检查的异常不需要在接口中声明,因此我们无法使用检查异常来处理它们。我们需要在 InvocationHandler#invoke
方法中捕获并重新抛出 UndeclaredThrowableException
异常。此时 UndeclaredThrowableException
异常的 getCause()
方法返回实际抛出的异常,这个例子中就是 RuntimeException
。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:jdk中动态代理异常处理分析:UndeclaredThrowableException - Python技术站