【Javassist】快速入门系列03 使用Javassist实现方法异常处理

news2025/2/4 18:01:22

系列文章目录

01 在方法体的开头或结尾插入代码
02 使用Javassist实现方法执行时间统计
03 使用Javassist实现方法异常处理


文章目录

  • 系列文章目录
  • 前言
  • 引入Javassist jar包
    • 使用Javassist实现方法异常处理
  • 总结
  • 说明


前言

上一章我们介绍了使用使用Javassist实现了对方法执行时间的统计,学会了Javassist在方法体前后插入代码和为类新增字段。本章主要介绍使用Javassist为方法实现异常处理。


引入Javassist jar包

在上几篇文章已经引入了javassist的jar包,如果你是第一次观看本系列文章,也可以复制以下maven依赖将jar包导入工程。本篇文章还用到了commons-lang3jar包中的org.apache.commons.lang3.exception.ExceptionUtils工具类。

        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.28.0-GA</version>
        </dependency>
         <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

使用Javassist实现方法异常处理

/**
 * 【Javassist】快速入门系列03 使用Javassist实现方法异常处理
 * 公众号&B站:精致的王同学
 * @author 精致的王同学
 * @date 2022/12/19 22:31
 */
public class Basic03ExceptionHandle {
    public static void main(String[] args) throws Exception {
        // 创建javassist默认类池
        ClassPool pool = ClassPool.getDefault();
        //获取basic.SkuService的Ctclass文件
        CtClass ctClass = pool.get("basic.SkuService");
        // 获取SkuService的getSkuProfitRate方法
        CtMethod method = ctClass.getDeclaredMethod("getSkuProfitRate");
        // 获取要捕获的异常类型
        CtClass etype  = pool.get("basic.ErrorCodeException");
        // 给方法添加异常处理
        method.addCatch("{ System.out.println(org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace($e));;\n " +
                "//todo 模拟将异常错误码、提示及堆栈信息插入数据库 \n" +
                " throw $e;}",etype);
        // 将类写入文件
        ctClass.writeFile();
        // 获取类的clazz文件
        Class<?> skuServiceClazz = ctClass.toClass();
        // 实例化类的对象
        Object obj = skuServiceClazz.newInstance();
        // 获取类的修改后方法
        Method getSkuProfitRate = skuServiceClazz.getDeclaredMethod("getSkuProfitRate",Long.class);
        // 调用修改后的getSkuProfitRate方法
        Object skuProfitRate = getSkuProfitRate.invoke(obj, (Object) 1l);
        System.out.println("sku的利润率为:"+skuProfitRate);
    }
}

以上Basic03ExceptionHandle类创建了一个main方法,该方法中首先获取javassist的类池pool,然后调用pool.get(“basic.SkuService”)方法获取到basic包下的SkuService类。SkuService类源码如下:

/**
 * 库存业务类
 * 公众号&B站:精致的王同学
 * @author 精致的王同学
 * @date 2022/12/19 23:38
 */
public class SkuService {
    public BigDecimal getSkuProfitRate(Long skuId){
        // 模拟调用查价格接口获取商品原价和商品销售价
        BigDecimal originalPrice = null;
        originalPrice = getOriginalPrice(skuId);
        BigDecimal salePrice = getSalePrice(skuId);
        BigDecimal profit = salePrice.subtract(originalPrice);
        return profit.divide(originalPrice);
    }

    private BigDecimal getSalePrice(Long skuId) {
        return new BigDecimal(130.00);
    }

    private BigDecimal getOriginalPrice(Long skuId) {
        // 模拟sku原始价格为0,价格未初始化的情况
        BigDecimal originalPrice = new BigDecimal(0.00);
        if (BigDecimal.ZERO.compareTo(originalPrice) == 0) {
            throw new ErrorCodeException(10001,"sku原始价格不能等于0!");
        }
        return originalPrice;
    }
}

该类主要模拟获取sku销售利润比例。利润比例=(销售价-原价)/原价

回到Basic03ExceptionHandle的main方法中,在获取到basic.SkuService的ctClass对象后,获得了其声明的getSkuProfitRate方法的CtMethod对象。

然后通过调用pool.get(“basic.ErrorCodeException”)方法获取要捕获的异常类型,其中basic.ErrorCodeException的源码如下:

/**
 * 库存业务类
 * 公众号&B站:精致的王同学
 * @author 精致的王同学
 * @date 2022/12/19 23:38
 */
public class ErrorCodeException extends RuntimeException {
    private Integer code;
    private String msg;

    public ErrorCodeException(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ErrorCodeException(String message, String msg) {
        super(message);
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

然后调用method.addCatch(String src, CtClass exceptionType)方法为getSkuProfitRate方法添加catch语句。其中addCatch的第一个参数为catch子句中要执行的代码块,第二个参数为要捕获的异常类型。此例中为ErrorCodeException 的Ctclass类型。

我们捕获到错误码异常之后,在实际生产场景想要对异常错误码,错误信息,及堆栈信息插入到数据库中。后续在做个管理功能,方便研发排查错误。在此例中省略这些语句。其中$e代表被捕获的异常对象。拿到此对象便可拿到异常的详细信息。同时我们需借用org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e)获取异常的堆栈信息。

注意addCatch方法需以throw或return语句结尾。

最后调用 模拟调用javassist修改后的getSkuProfitRate方法。输出结果为:
getSkuProfitRate方法输出结果

总结

本篇文章介绍了使用Javassist实现方法异常处理,学习了Javassist的addCatch语句的用法。通过调用CtMethod的addCatch方法可以拦截特定类型的异常并对其进行处理。

说明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/103408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

07_哈希表

哈希表 1.为什么需要构建哈希表 现在有一组数据&#xff0c;我们想查找一个值&#xff08;x&#xff09;是否在这组数据中&#xff0c;通常来说&#xff0c;我们需要把这组数据遍历一遍&#xff0c;来看看有没有x这个值。 这时&#xff0c;我们发现这样查找数据要花费的时间…

C++ 类和对象

C认为万事万物都皆为对象&#xff0c;对象上有其属性和行为&#xff0c;C面向对象的三大特性为&#xff1a;封装、继承、多态。 一. 封装 封装是C面向对象三大特性之一。 封装的意义&#xff1a; 将属性和行为作为一个整体&#xff0c;表现生活中的事物将属性和行为加以权限控…

【数据库】时间戳并发控制

Timestamp ordering(T/O) 根据事务的时间戳来决定顺序。 如果T1 的时间戳小于T2 的时间戳&#xff0c;那么执行的结果要等价于T1 执行早于T2 的执行。 时间戳的实现策略&#xff1a; 系统时钟 逻辑计数 混合方法 Basic Timestamp Ordering&#xff08;T/O&#xff09;Prtot…

【WPF绑定2】 ComboBox MVVM SelectedValue复杂数据类型绑定

前言 这次绑定是一次非常痛苦的经历&#xff0c;因为SelectedValue总是不能生效&#xff01;我一度怀疑是wpf的Bug。其实还是自己没搞清楚。 在之前的一篇文章中&#xff1a; http://t.csdn.cn/A4W6Ahttp://t.csdn.cn/A4W6A我也写个ComboBox的绑定&#xff0c;但是当时没有指…

【实时数仓】DWM层订单宽表之实现基本的维度查询、加入旁路缓存模式

文章目录一 DWM层-订单宽表1 维表关联代码实现&#xff08;1&#xff09;首先实现基本的维度查询功能a 封装Phoenix查询的工具类PhoenixUtilb 封装查询维度的工具类DimUtil&#xff08;2&#xff09; 优化1&#xff1a;加入旁路缓存模式a 缓存策略的几个注意点b 缓存的选型c 在…

AnimateGAN 迁移部署

文章目录1. 模型概述2. 迁移过程2.1 将ckpt的权重文件转换为pb的权重文件。2.2 将pb的权重文件迁移为 BM1684 bmodel模型2.3 迁移后pipeline搭建2.4 使用streamlit部署3. 效果展示AnimateGAN 是一个基于 GAN 的动漫生成模型&#xff0c;可以将真实的场景照片转换成动漫形式。本…

CASA(Carnegie-Ames-Stanford Approach)模型

植被作为陆地生态系统的重要组成部分对于生态环境功能的维持具有关键作用。植被净初级生产力&#xff08;Net Primary Productivity, NPP&#xff09;是指单位面积上绿色植被在单位时间内由光合作用生产的有机质总量扣除自养呼吸的剩余部分。植被NPP是表征陆地生态系统功能及可…

设计模式之美总结(创建型篇)

title: 设计模式之美总结&#xff08;创建型篇&#xff09; date: 2022-11-03 13:58:36 tags: 设计模式 categories:技术书籍及课程 cover: https://cover.png feature: false 文章目录1. 单例模式&#xff08;Singleton Design Pattern&#xff09;1.1 为什么要使用单例&…

如何在高密度的IB学习中杀出重围?

建议选择IB所需具备的能力/特点 ▣ 敢于挑战自我&#xff0c;愿意通过努力换取个人能力的飞跃 ▣ 如果擅长或喜欢写作&#xff08;中英文&#xff09;&#xff0c;IB对于你来说可能不会那么难。 ▣ 有自主学习、自主研究的能力。有些老师可能教的并不太让人满意&#xff0c;因此…

OpenTelemetry系列 (三)| 神秘的采集器 - Opentelemetry Collector

前言 上个篇章中我们主要介绍了OpenTelemetry的客户端的一些数据生成方式&#xff0c;但是客户端的数据最终还是要发送到服务端来进行统一的采集整合&#xff0c;这样才能看到完整的调用链&#xff0c;metrics等信息。因此在这个篇章中会主要介绍服务端的采集能力。 客户端数…

学Python能做哪些副业?我一般不告诉别人

前两天一个朋友找到我吐槽&#xff0c;说工资一发交完房租水电&#xff0c;啥也不剩&#xff0c;搞不懂朋友圈里那些天天吃喝玩乐的同龄人钱都是哪来的&#xff1f; 确实如此&#xff0c;刚毕业的大学生工资起薪都很低&#xff0c;在高消费、高租金的城市&#xff0c;别说存钱…

日志篇- ES+Logstash+Filebeat+Kibana+Kafka+zk 安装配置与使用详解

1- 学习目标 ELK基本概念&#xff0c;特点安装部署 Kibana ES集群 Logstash Filebeat Kafka集群性能瓶颈以及优化QA汇总 2- 介绍 2.1- 基本概念 Elasticsearch 分布式搜索和分析引擎&#xff0c;具有高可伸缩、高可靠和易管理等特点。基于 Apache Lucene 构建&#xff0c…

xv6---Lab4 traps

参考&#xff1a; Lab: Traps 关于寄存器s0和堆栈https://pdos.csail.mit.edu/6.828/2020/lec/l-riscv-slides.pdf RISC-V assembly Q: 哪些寄存器包含函数的参数?例如&#xff0c;哪个寄存器在main对printf的调用中保存了传参13 ? A: a2保存13(通过gdb调试可看出寄存器a2的…

【设备管理系统】如何助力制造企业实现精益生产?

随着企业对于机械设备的依赖性越来越高&#xff0c;生产设备日益大型化、自动化&#xff0c;流程线生产流程问题逐渐浮于表面&#xff0c;现阶段设备管理的各项制度已经不能够满足日常的生产工作。企业逐渐都面临着设备管理的复杂问题&#xff0c;尤其是设备的保养、维修、日常…

JMeter—HTTP压测

目录&#xff1a;导读 一、创建线程组 二、添加HTTP 三、查看结果树 四、响应断言 五、聚合报告 六、自定义变量 七、CSV可变参数压测 结语 一、创建线程组 右击-->添加-->Threads(Users)-->线程组 下面对比较重要的几个参数&#xff0c;讲解下&#xff1a; …

Vue基础7

Vue基础7生命周期引出生命周期用css animation实现用定时器实现错误&#xff1a;用methods实现使用生命周期函数mounted实现生命周期定义分析生命周期挂载流程beforeCreate()created()beforeMount()mounted()template的作用更新流程beforeUpdate()updated()销毁流程beforeDestr…

【数据库】二阶段锁

Two-phase locking (2PL) is a concurrency controlprotocol that determines whether a txn can access an object in the database on the fly. The protocol does not need to know all the queriesthat a txn will execute ahead of time. 分为两个阶段&#xff1a; 一阶…

颅内EEG记录揭示人类DMN网络的电生理基础

使用无创功能磁共振成像&#xff08;fMRI&#xff09;的研究为人类默认模式网络&#xff08;DMN&#xff09;的独特功能组织和深远重要性提供了重要的见解&#xff0c;但这些方法在跨多个时间尺度上解决网络动力学的能力有限。电生理技术对于应对这些挑战至关重要&#xff0c;但…

RAID 0 添加新磁盘

1&#xff1a;查看当前可用挂载磁盘 lsblk 2&#xff1a;可见 sda 与 sdb 已被挂载&#xff0c;需要挂载 sdc 和 sdd 由于硬盘的默认分区格式是MBR&#xff0c;这种格式的硬盘支持的最大挂载容量为2T&#xff0c;为了满足我们的要求&#xff0c;需要将硬盘格式转化为MBR&…

Node.js 编写接口入门学习(GET、POST)

一、简介 nvm 安装、卸载与使用&#xff08;详细步骤&#xff09;&#xff0c;用于管理/切换 Node 多版本环境。 node 是否安装成功 $ node -v安装完成之后&#xff0c;通过 node 直接运行 test.js。 // test.js console.log(Hello Node)# 命令行执行 $ node test.js二、简单的…