Javassist分析类依赖和动态代理实现

前言

Javassist作为一款强大的class编辑器,它能够读取class文件内容,class文件的常量池中包含了当前类所有需要交互的其他类。要获取当前类所有依赖的类,只需要先获取当前类直接依赖的类,再继续广度优先遍历直接依赖类依赖的类,最终遍历了整棵依赖树之后就能获取当前类依赖。对于动态代理其实也是通过在运行过程中动态新的代理类,代理类不但会增加额外的用户逻辑,还会调用被代理对象的对应方法,Javassist强大的类编辑功能能够很好的完成这个任务。

类依赖实现

首先需要定义当前类直接依赖的类有哪些,首先继承的父类很显然是当前类一定会依赖的,接下来是当前类实现的接口,接着是定义的字段值类型,最后就是方法传入参数类型、返回参数类型还有方法中使用到其他工具类。得到这些直接依赖的类之后,需要再获取这些直接依赖类直接依赖的类,我们发现这时候问题变成了上面的问题,只不过当前类变成了当前类依赖的其中一个类,递归调用就可以解决这种重复问题。

前面讲解Class文件格式的时候讨论过如何使用Javassist来获取父类、接口和方法中依赖的类,不过里面并不完全,还缺少实现接口类、方法签名里的类型,我们可以通过方法签名的分析得到使用到的类。

/**
 * 查看某个类引用的所有类
 * @param clazz
 * @param set
 * @throws NotFoundException
 */
private static void bfs(String clazz, Set<String> set) throws NotFoundException {
    CtClass ctClass = ClassPool.getDefault().get(clazz);
    // 当前类直接依赖的类
    Set<String> levelClasses = new TreeSet<>();
    ClassFile classFile = ctClass.getClassFile();

    /**
     * 遍历代码内使用的类,包含方法实现里使用的类,不包含方法签名里的类
     */
    for (String className : classFile.getConstPool().getClassNames()) {
        if (className.startsWith("[L")) {
            className = className.substring(2, className.length() - 1);
        } else if (className.startsWith("[")) {
            continue;
        }
        className = getClassName(className);
        addClassName(set, levelClasses, className);
    }

    /**
     * 获取父类
     */
    String superClass = classFile.getSuperclass();
    if (!"".equals(superClass) && superClass != null && !set.contains(superClass)) {
        levelClasses.add(superClass);
        set.add(superClass);
    }

    /**
     * 获取所有接口
     */
    String[] interfaces = classFile.getInterfaces();
    if (interfaces != null) {
        for (String face : interfaces) {
            String className = getClassName(face);
            addClassName(set, levelClasses, className);
        }
    }

    /**
     * 获取字段的类型
     */
    List<FieldInfo> fieldInfoList = classFile.getFields();
    if (fieldInfoList != null) {
        for (FieldInfo fieldInfo : fieldInfoList) {
            String descriptor = fieldInfo.getDescriptor();
            if (descriptor.startsWith("L") && descriptor.endsWith(";")) {
                String className = descriptor.substring(1, descriptor.length() - 1);
                className = getClassName(className);
                addClassName(set, levelClasses, className);
            }

            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值