bytebuddy实现原理分析 &源码分析 (二)

bytebuddy实现原理分析 &源码分析(一)
bytebuddy实现原理分析 &源码分析 (二)
bytebuddy实现原理分析 &源码分析 (三)
bytebuddy实现原理分析 &源码分析 (四)

四、字节码的操作(implementation ) pkg

在这里插入图片描述
byte buddy中对字节码的操作,直接调用了asm的api。
比如 FixedValue 是修改方法时定义返回的值,比如toString()=="hello"改成toString()=="changed",这个意味着要把.class字节码中的变量"hello" 替换成"changed"

如果是修改方法的定义,比如methodCall。就要修改字节码指令,本地变量栈和操作数栈。

方法的编译成字节码后就是,字节码指令和本地变量栈和操作数栈。完成方法的逻辑,就是顺序的执行字节码指令操作栈帧。不了解的同学可以先去补充字节码的知识。

asm 本身包含了字节码的各类模型,并且提供API来修改。但是这是low-level级别的。比如我要定一个加法运算,就要使用API生成多个字节码指令

byte buddy 就是对这样大量重复的操作做了上层的封装。

源码关于字节码的实现可以大概分为两部分: 字节码封装操作字节码的API

4.1 bytecode :pkg

对字节码的封装
在这里插入图片描述

4.1.1 StackManipulation :cls

代表生成方法的操作数栈
在这里插入图片描述
方法

方法名 描述
boolean isValid() 判断生成的操作数栈是否合法
Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext); methodVisitor是asm的接口用来生成字节码,Implementation.Context中定义了字节码。这个函数的作用是应用定义的字节码

内部类
在这里插入图片描述

方法名 类型 描述
Illegal 实现 非法的实现
Trivial 实现 合法的实现,但是不会对原先的字节码有任何更改
Compound 实现 可以对多个方法的栈大小进行合并运算
4.1.1.1 StackManipulation的子类实现
类名 类型 描述
Addition 实现 操作数栈的数字想加
Duplication 实现 复制栈定的数
Multiplication 实现 操作数栈的数字相乘
Removal 实现 移出操作数栈的值
TypeCreation 实现 当一个构造器方法被调用时,创建一个未定义的类型
Throw 实现 必须位于栈顶,当StackManipulation被调用时抛出一个异常java.lang.Throwable

看一个具体的例子Duplication, 其他的方法也类似: 封装字节码指令;重写apply
示例
复制一个在操作数栈,复制一个double 类型的数。和普通int不一样,long和double需要占1到2卡槽(2* 4 byte)。 所以这个枚举变量DOUBLE,和字节码指令int DUP2 = 92;关联。
封装字节码指令

  /**
     * A duplication of a double-sized stack value.
     */
    DOUBLE(StackSize.DOUBLE, Opcodes.DUP2) {
   
        @Override
        public StackManipulation flipOver(TypeDefinition typeDefinition) {
   
            switch (typeDefinition.getStackSize()) {
   
                case SINGLE:
                    return WithFlip.DOUBLE_SINGLE;
                case DOUBLE:
                    return WithFlip.DOUBLE_DOUBLE;
                default:
                    throw new IllegalArgumentException("Cannot flip: " + typeDefinition);
            }
        }
    };

新建一个Duplication,有两个方法

	/** 直接输入栈大小,和字节码指令
	*/
    Duplication(StackSize stackSize, int opcode) {
   
        size = stackSize.toIncreasingSize();
        this.opcode = opcode;
    }
    /**
    *  根据类型的定义,获取栈大小
    */
    public static Duplication of(TypeDefinition typeDefinition) {
   
        switch (typeDefinition.getStackSize()) {
   
            case SINGLE:
                return SINGLE;
            case DOUBLE:
                return DOUBLE;
            case ZERO:
                return ZERO;
            default:
                throw new AssertionError("Unexpected type: " + typeDefinition);
        }
    }

实现apply
看看apply的实现,核心是methodVisitor.visitInsn(opcode);这就是asm原生的方法,作用实在字节码码中生成这么一个指令。

    public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
   
        methodVisitor.visitInsn(opcode);
        return size;
    }

4.1.2 assign :pkg

在这里插入图片描述
这个包封装了jvm规范中的两个基本类型:基本类型,引用类型。负责控制不同类型之间的转换

4.1.2.1 Assigner : cls

一个Assigner负责把一个类型A转换成类型B。比如一个Assigner可以负责类型转化:装箱,把一个基本类型(int),转化为包转类(Integer);拆箱,正好相反。
在这里插入图片描述

1 Typing: in & cls

指示,累型的转化是静态的还是动态的。静态的意思是,调用前已经确定了。动态类型时,生成是才确定。默认值是动态生成。

 		/**
         * 静态生成
         */
        STATIC(false),

        /**
         * 动态生成
         */
        DYNAMIC(true);
2 核心方法: in
  • StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing);
3 EqualTypesOnly : in & impl

Assigner的实现。

 enum EqualTypesOnly 
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值