JDK动态代理UndeclaredThrowableException异常

2023-11-11

UndeclaredThrowableException异常背景

最近项目上出现了 JDK动态代理UndeclaredThrowableException异常,此异常之前没有接触过,那么该异常将会导致什么呢?

UndeclaredThrowableException后果:导致该抛出的直接异常信息被包装了好几层,异常看起来很费事,如下图:

产生原因

要了解其原因的前提条件是必须了解检查型异常和非检查型异常,了解的话请查看这个链接:检查型异常和非检查型异常 

为什么会产生UndeclaredThrowableException异常呢?通过查阅javadoc官方文档(链接地址:https://docs.oracle.com/javase/6/docs/api/java/lang/reflect/InvocationHandler.html),发现了该异常抛出的条件,如下图:

上述原因翻译成关键一句就是:如果抛出的异常是检查型异常,而代理类在处理异常时没有发现该类型的异常在接口中声明

这种话是什么意思呢?下面结合代码给大家讲述一下,动态代理之后会生成$Proxy0.class文件,至于怎么生成并查看这个文件,请查看这个链接:JDK动态代理文件$Proxy0.class的生成和查看, $Proxy0.class 文件内容说明了如何抛出了UndeclaredThrowableException异常,如下图:

通过JDK动态代理代码调用我们发现,method.invoke(target, args) 将会抛出 InvocationTargetException ,InvocationTargetException 异常属于检查型异常,如下图:

代码中接口声明的是非检查型异常RuntimeException,因此会抛出 UndeclaredThrowableException异常,示例demo如下所示:

// 自定义异常

public class CustomException extends RuntimeException {
    private static final long serialVersionUID = -5427543428947291283L;

    public CustomException(String message) {
        super(message);
    }
}

// 接口

public interface AccountService {
    void getAccount() throws RuntimeException;
}

// 实现类

public class AccountServiceImpl implements AccountService {
    @Override
    public void getAccount() throws RuntimeException {
        try {
            System.out.println(1/0);
        } catch (Exception e) {
            throw new CustomException("账户查询异常:" + e);
        }
    }
}

// JDK动态代理类

public class AccountProxy implements InvocationHandler {
    private Object target;

    public AccountProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }
}

// 测试类

public class ProxyTest {
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        AccountService accountService = new AccountServiceImpl();
        AccountService accountServiceProxy = (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(), new AccountProxy(accountService));

        try {
            accountServiceProxy.getAccount();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

避免抛出 UndeclaredThrowableException异常

那么针对上述代码,我们怎么样避免UndeclaredThrowableException异常的抛出呢?我们既然知道了该异常的抛出原因,那么只需要简单修改一下就可以避免此异常的抛出,即只需要将接口中抛出的异常修改为检查型异常即可,如下所示:

// 接口中的 RuntimeException 修改为了 Exception

public interface AccountService {
    void getAccount() throws Exception;
}

代理类 $Proxy0.class 如下图所示:

注意: 这里的异常类型和你自定义异常的类型无关吗,只和代理类接口中声明的异常类型有关

完美的解决方案

我们不管代理接口中声明的抛出类型是什么,我们只想看到自己抛出的直接的异常,UndeclaredThrowableException异常 和 InvocationTargetException 异常都不想看到,这样更容易定位到问题。解决方案就是在 method.invoke(target, args) 进行 InvocationTargetException 异常的捕获,代码如下:

// method.invoke(target, args) 方法调用地方增加了 InvocationTargetException 异常的捕获

public class AccountProxy implements InvocationHandler {
    private Object target;

    public AccountProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            return method.invoke(target, args);
        } catch (InvocationTargetException e) {
            throw e.getCause();
        }
    }
}

运行结果如下图所示:

总结

通过上述分析可知,当我们使用JDK动态代理的时候,需要捕获 method.invoke(target, args) 抛出的 InvocationTargetException 异常

代理类中为什么对未声明的检查型异常转换为 UndeclaredThrowableException 异常呢?答案是 java 继承原则,即子类覆盖父类方法或者实现父类方法时,抛出的异常必须在父类支持的异常列表之内。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JDK动态代理UndeclaredThrowableException异常 的相关文章

  • 阿里云—(1)安装JDK 11

    1 查看原有JDK版本 若新装系统 可忽略 yum list installed grep java 如图所示 代表已安装 2 查看yum库内所有的JDK版本 yum y list java 当你已经安装了某个版本后 显示的为本地安装包 下
  • Java基础学习之函数式编程Comsumer接口(JDK8)

    前言 从毕业到现在正好三年 高难度的项目做了不少 但是基础这个东西一段时间不接触就会忘得一干二净 话不多说 开始今天的学习 1 Consumer接口 接触过 消费者 生产者 模式的同学 肯定对这个单词不陌生 在java8函数式编程和lamb
  • Window11下载安装jdk8-jdk11与环境变量的配置

    目录 1 下载jdk 1 1 jdk8下载链接 请点击网址 1 2 jdk11下载链接 请点击网址 2 安装jdk 3 配置环境变量 3 1 打开设置 3 2 点击系统信息 3 3 高级系统设置 3 4 点击环境变量 3 5 新建系统变量
  • jdk 16中改进的ZGC

    内存对象重定位的优化 预留堆空间 heap reserve 是堆空间中特殊的一块小空间 无法用于java线程的常规分配 而当发生gc时需要进行对象重分配时才会使用 此举确保了空的堆区域可用 即使是在java线程角度看堆空间已满 仍可进行对象
  • Linux下jdk的下载安装

    将jdk放到Linux中 由于jdk现在不好下载了 所以笔者通过网上查找合适的资源之久 直接上传到服务器上 解压 进入jdk所在目录键入下面的命令进行解压 tar zxvf jdk 8u241 linux x64 tar gz 如下图所示
  • jdk下载百度云(windows×64-7,8,10)

    之前找了很久 好多都要很多积分 所以我就给大家整理到百度云盘 https pan baidu com s 1UgiZf6R8PNtnlTDNW N2Kw 提取码 o6cp
  • Mac下jdk的安装路径

    http hi baidu com liouyan9 blog item 78fdc009b97bdac63ac76377 html Mac下jdk的安装路径 2009 08 11 15 39 苹果系统已经包含完整的J2SE 其中就有JDK
  • 使用 java 命令编译运行 java 程序

    java 编译的过程 就是将 java 项目从源文件变成 class 文件的过程 而 class 文件 最后会被加载到JVM 中运行 在 JDK bin 目录下 提供了 javac 命令 用于将 java 源文件编译成 class 字节码文
  • 聊聊你不知道的Java变量转型

    单枪匹马你别怕 一腔孤勇又如何 这一路你可以哭 但不能怂 请关注 源码猎人 目录 简介 标识符命名规则 类变量 静态变量 实例变量 局部变量 变量数据类型 基本类型之间的转换 常见面试题 简介 Java变量分为类变量 实例变量 局部变量 在
  • 使用yum命令安装jdk1.8没有jps命令

    问题 使用yum命令安装jdk1 8后 不能使用jps 这是由于没有openjdk devel这个包 使用yum命令下载 yum install java 1 8 0 openjdk devel x86 64 下载完成之后就可以使用jps命
  • 解决tomcat安装配置后localhost 打不开

    为了这只丑猫能用的方法都用了 终于出来了 也不知道到底哪些是必须的 建议 1 检查端口8080是否被占用 被占用的话参照下方改端口 2 环境变量肯定是要配置的 3 如果以上不可以 那么什么方法都试试吧 前提 下载安装tomcat9和jdk
  • centos7 安装jdk17

    默认情况下 yum 仓库中是没有jdk 17 的 只有jdk 11 所以我们不能直接用yum 安装 需要手动下载进行配置工作 下载文件 wget https download oracle com java 17 latest jdk 17
  • 基于JDK1.8 的LinkedList源码分析

    基于JDK1 8 的LinkedList源码分析 代码注释 JDK版本 jdk1 8 0 181 package java util import java util function Consumer Doubly linked list
  • linux安装jdk之后,系统默认使用openjdk解决方法

    前两天装了个虚拟机配置java环境变量之后 java version 发现使用的仍然是 openjdk 咨询了下公司里的大神 成功解决 我配置的环境变量 export JAVA HOME home hadoop softwares jdk1
  • (一)win10安装hadoop 2.8.5(详细步骤)

    目录 1 JDK 2 Hadoop 2 1 下载 2 2 配置环境变量 2 3 配置文件 2 4 格式化hdfs 已解决 格式化总是报错 The markup in the document following the root eleme
  • JDK1.8 AbstractQueuedSynchronizer的实现分析(上)

    深度解析Java 8 JDK1 8 AbstractQueuedSynchronizer的实现分析 上 作者 刘锟洋 发布于 2014年7月31日 http www infoq com cn articles jdk1 8 abstract
  • 浅谈Class.forName()在JDBC中的作用

    目录 1 Class forName 有什么作用呢 2 为什么不直接new 3 为什么删除Class forName com mysql jdbc Driver 还是可以运行 JDBC是Bridge模式的典型应用 DriverManager
  • jdk8源码之Queue-ArrayQueue

    关于队列这个数据结构 大家应该都是比较熟悉 列队是一种先进先出 FIFO 的数据结构 删除操作只能在表的头部 插入操作只能在表的尾部 Queue一般是作为一个缓冲队列使用的 简单举例 生产端的生产速度偶尔会大于消费端的消费速度 但又不想等待
  • Java Web快速开发(1)Java 项目构建

    文章目录 Java 项目构建 1 Java 版本发展 2 集成开发环境 3 Java发布形式 1 扩展参数说明 2 JVM 内存回收机制 3 Java 程序分析调测工具 4 Maven Java 项目构建 1 Java 版本发展 EJB E
  • 服务器乱码专栏问题一:String.getBytes()获取值乱码

    本文建议阅读时长 15mins 前记 最近笔者工作比较繁忙 导致本来应该有很多博客需要填坑 一直也没有静下心来好好整理下 今天蹭着夜深人静加之阵阵柔和的轻音乐正好先写上一篇 也算是为自己乱码专栏开个头 当然本专栏主要解决Tomcat服务器以

随机推荐

  • Python实现删除某列中含有空值的行

    客户需求 查看销售人员不为空值的行 数据存储情况如图 代码实现 import pandas as pd data pd read excel test xlsx sheet name Sheet1 datanota data data 销售
  • TensorFlow:常用函数介绍

    学习网址 Tensorflow中文社区 http www tensorfly cn 一 tensorflow框架笔记 1 Variable 一个Variable代表一个可修改的张量 存在在TensorFlow的用于描述交互性操作的图中 它们
  • C程序头文件注释格式

    Copyright C 2010 2011 Your Company FileName 文件名 Author 作者 Version 版本 Date 完成日期 Description 用于主要说明此程序文件完成的主要功能 与其他模块或函数的接
  • 蓝牙设备上电提示Failed to set power on: org.bluez.Error.Blocked

    NEW Controller 74 2F 68 6A 37 44 moon 0 default NEW Device 00 07 61 76 8E 78 Logitech diNovo Edge Agent registered bluet
  • 03. 微信公众号消息接收、事件推送与响应处理

    1 消息接收 官方文档 当普通微信用户向公众账号发消息时 微信服务器将POST消息的XML数据包到开发者填写的URL上 gt 接口配置信息的URL 即开发时 接收信息的接口的访问路径与微信接入的URL一致 但为 POST 请求 请求参数 依
  • 计算机毕业设计Java的工资管理系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java的工资管理系统 源码 系统 mysql数据库 lw文档 计算机毕业设计Java的工资管理系统 源码 系统 mysql数据库 lw文档 本源码技术栈 项目架构 B S架构 开发语言 Java语言 开发软件 idea ec
  • QA 如何打造自身的核心竞争力?

    转载自微服务质量保障 20 讲嘉木老师 怎样理解 核心竞争力 在讲解竞争力之前先看下什么是能力 能力是指一个人完成一个目标或者任务所体现出来的素质 如技能 知识 经验以及行为等 解释中暗含了 能力是一个绝对值 正数 的意思 显得比较学术 而
  • 360度全景标定方法_一种360度全视角鸟瞰全景行车辅助标定方法与流程

    技术领域本发明涉及辅助驾驶领域 具体地说是一种360度全视角鸟瞰全景行车辅助标定方法 背景技术 随着图像和计算机视觉技术的快速发展 越来越多的技术被应用到汽车电子领域 传统的基于图像倒车影像系统在车尾安装摄像头 只能覆盖车尾周围有限的区域
  • 【Vue3源码】第四章 实现isReadonly和isReactive

    Vue3源码 第四章 实现isReadonly和isReactive 前言 上一章节我们实现readonly API 并且优化之前写的reactive API 这一章我们实现isReadonly和isReactive两个API 1 实现is
  • Vue中对于指令的介绍

    Vue指令 文章目录 Vue指令 1 介绍 2 指令介绍 2 1 v html 2 2 v show和v if 3 2 v else 和 v else if 3 3 v on 3 4 v bind 3 5 v for 3 6 v for 中
  • (十二)Mybatis鉴别器discriminator和延迟加载的用法

    这篇文章主要讲述Mybatis鉴别器discriminator和延迟加载的用法 对大家的学习或者工作具有一定的参考学习价值 需要的朋友们下面随着小编来一起学习学习吧 目录 什么是鉴别器 代码示例 总结 什么是鉴别器 mybatis可以使用d
  • 微信小程序 - 修改 button 边框和背景色

    为什么80 的码农都做不了架构师 gt gt gt 微信小程序开发中使用 button 设置禁用时候 按钮会有默认的背景色和边框 下面分享下修改按钮边框和背景色 wxml代码
  • 简述SQL Server内存不断增加的原因,以及如何解决该问题。

    在启用sqlserver服务后 发现进程sqlservr exe的内存使用量从开始的100多MB持续增加 很快就高达1G以上 造成机器运行缓慢 卡机 严重影响使用 sql server 在查询大数据量的数据时 总会占用大量的内存 并且居高不
  • centos7和centos6区别:

    1 内核 centos7的内核用的是3 10 centos6的内核用的是2 6 2 文件系统 centos6 X EXT4 EXT4的单个文件系统容量达到1EB 单个文件大小则达到16TB centos7 X XFS XFS默认支持8EB见
  • c++继承中的内存布局(转)

    今天在网上看到了一篇写得非常好的文章 是有关c 类继承内存布局的 看了之后获益良多 现在转在我自己的博客里面 作为以后复习之用 谈VC 对象模型 美 简 格雷 程化 译 译者前言 一个C 程序员 想要进一步提升技术水平的话 应该多了解一些语
  • ceph分布式存储-常见OSD故障处理.md

    2 常见 OSD 故障处理 进行 OSD 排障前 先检查一下 monitors 和网络 如果 ceph health 或 ceph s 返回的是健康状态 这意味着 monitors 形成了法定人数 如果 monitor 还没达到法定人数 或
  • C++——STL容器

    首先 适配器的概念 适配器的意思就是将某些已经存在的东西进行限制或者组合变成一个新的东西 这个新的东西体现一些新的特性 但底层都是由一些已经存在的东西实现的 STL中的容器 vector 矢量 并非数学意义上的 STL最简单的序列类型 也是
  • Redis 安装系统服务报错 HandleServiceCommands: system error caught. error c ode=1073, message = CreateS

    系统已经存在该服务 需要先卸载才能重新安装 点击查看详细操作链接
  • ARC149题解

    ARC149 没有 F 题 A A A 题意 给定 n m 找到一个数字长 n 位 每位数字都相同且是 m 的倍数 题解 直接模拟 代码 B B B 题意 给定序列 A B 每次可以同时交换
  • JDK动态代理UndeclaredThrowableException异常

    UndeclaredThrowableException异常背景 最近项目上出现了 JDK动态代理UndeclaredThrowableException异常 此异常之前没有接触过 那么该异常将会导致什么呢 UndeclaredThrowa