jdk中动态代理异常处理分析:UndeclaredThrowableException

yizhihongxing

当使用 JDK 动态代理时,如果目标方法抛出一个未在代理接口上声明的异常时,会发生 UndeclaredThrowableException 异常。这个异常用于包装仅在运行时可知的受检查异常或 “错误”(Error)类型的异常(例如 java.io.IOExceptionjava.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技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • Java 进行时间处理的步骤

    Java 进行时间处理的步骤可以分为以下几个方面: 获取当前时间 Java 可以使用 java.util.Date 或 java.time.LocalDateTime 类获取当前的系统时间。其中,java.util.Date 是一个在 Java 8 之前使用的类,而在 Java 8 及以后,建议使用 java.time.LocalDateTime 类。 示例…

    Java 2023年5月20日
    00
  • dubbo自定义异常的完整步骤与测试

    下面我会详细讲解“dubbo自定义异常的完整步骤与测试”的完整攻略: 规划异常类包结构 首先应该规划好异常类的包结构。通常情况下,我们会把异常类放在com.xxx.exception包中,这个包可以在provider、consumer、api中共用。在com.xxx.exception包中,我们可以建立一些子包,如com.xxx.exception.comm…

    Java 2023年5月27日
    00
  • Spring ProtocolResolver策略接口示例

    下面我给出关于Spring ProtocolResolver策略接口示例的详细攻略。 策略接口概述 在Spring框架中,策略(Strategy)模式是一种常见的设计模式,它可以将不同的实现算法封装在不同的策略类中,并且这些策略类可以互相替换。Spring框架充分利用了策略模式的优势,因为它可以将不同的实现逻辑分离开来,使得代码更加灵活和可扩展。 Proto…

    Java 2023年5月23日
    00
  • 什么是Java安全管理器?

    Java安全管理器是Java运行时环境提供的一种访问控制机制,用于控制Java程序的访问权限。它的作用是为Java程序提供安全保障,限制其对系统资源的访问和操作,保证程序的安全性。 Java安全管理器可以通过在程序运行时设置Java安全策略文件来实现,这个策略文件定义了一组规则,规定了Java程序可以访问哪些资源、以什么方式访问、如何检查访问权限等。通过使用…

    Java 2023年5月11日
    00
  • java 日期各种格式之间的相互转换实例代码

    下面是 “Java 日期各种格式之间的相互转换实例代码” 的完整攻略: 基本介绍 在Java中,可以使用java.text.SimpleDateFormat类来格式化日期,具体的格式定义可以参考Java官方文档中的SimpleDateFormat类说明(notes)。在这个过程中,需要注意日期格式的大小写,具体规则请参考文档说明。 日期转换 以下是实现日期转…

    Java 2023年5月20日
    00
  • Window下安装JDK1.8+Tomcat9.0.27+Mysql5.7.28的教程图解

    下面我将详细讲解“Window下安装JDK1.8+Tomcat9.0.27+Mysql5.7.28的教程图解”的完整攻略。 前置要求 在安装这三个软件之前,需要先确定你的电脑已经满足以下几个前置要求: 操作系统:Windows 7/8/10 硬件配置:2GB 以上内存,至少 3GB 的硬盘空间 网络环境:需要能够联网,方便软件下载和安装 JDK1.8 的安装…

    Java 2023年6月2日
    00
  • 什么是元空间?

    以下是关于 Java 元空间的详细讲解和使用攻略: 元空间的作用是什么? Java 元空间(Metaspace)是一种用于存储加载类信息、常量、静态变量、即时编译后的代码数据的内存区域。元空间是线程共享的,其大小可以通过 -XX:MaxMetaspaceSize 参数进行设置。 元空间的使用攻略 使用 Java 元空间,需要注意几点: 在程序开发中需要合理使…

    Java 2023年5月12日
    00
  • 详解SpringBoot与SpringCloud的版本对应详细版

    下面是详解SpringBoot与SpringCloud的版本对应详细版的攻略: 为什么需要版本对应 Spring Boot 和 Spring Cloud 都是 Spring 生态圈中重要的组件,它们的版本号关系非常密切。由于两者的版本号之间存在依赖关系,当它们的版本不兼容时会导致异常等问题。如果不按照规则来进行版本搭配,则极有可能出现版本兼容性问题,从而导致…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部