文章目录

  • 前言
  • 引入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方法。输出结果为:

javassist 配置 javassist包_javassist 配置

总结

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

说明