Java 字節碼增強技術 2019-02-01

本文將介紹有哪些常見的字節碼增強技術、字節碼增強的實現方式、AOP實現的原理。

1. 字節碼增強技術的應用場景:

????寫日志、事務管理

????常見的字節碼增強技術:

????1. Java 動態代理

? ? ????Java Proxy API 通過invoke方法攔截出來相應的代碼邏輯。Proxy 是面向接口的,被代理的Class的所有方法調用都會通過反射調用invoke方法。

????????缺點:性能開銷大

????2.? Java 5 提供的Instrumentation API

? ? ? ? 適應場景:適用于監控

? ? ? ? 缺點:不適合處理靈活的代碼邏輯

? ? ? ? Instrumentation API 不僅可以做字節碼增強,還可以通過調用getObjectSize(Object o) 方法來計算一個對象的精確大小。

? ? 3. ASM?

? ? ? ? ASM 是一個提供字節碼解析和操作的框架。CGlib 框架是基于ASM 實現,而常用的框架Hibernate、Spring 是基于CGlib 實現 AOP的。

? ? ? ? ASM 對使用者屏蔽了整個類的字節碼的長度、偏移量,能夠靈活、方便地解析和操作字節碼。主要提供 Core API 和Tree API。

? ? ? ? Core API 主要的類(接口):

? ? ? ? ? ? ClassVisitor、ClassAdapter、ClassReader、ClassWriter

? ? ? ? Tree API 主要的類(接口):

? ? ? ? 工具類:

? ? ? ? ? ? TraceClassVisitor、CheckClassAdapter、ASMifier、Type

? ? ? ? ? ? TraceClassVisitor 能打印ClassWriter 提供的byte[] 字節數組。

? ? ? ? ? ? TraceClassVisitor 通過初始化一個ClassWriter 和一個Printer 對象來打印我們需要的字節流信息。方便比較類文件及分析字節碼文件的結構。


2. 兩種實現機制:

? ? (1) 通過創建原始類的一個子類(動態創建的類繼承原來的類)。子類名以原始類名為前綴,以避免重名。Spring AOP 使用的就是這種

? ? (2) 直接修改原始類的字節碼。類的跟蹤過程中使用

3. 實現字節碼增強要執行兩個步驟:

? ? (1) 在內存中獲取到原始的字節碼, 然后通過一些開源的API 來修改它的byte[] 數組,得到一個新的byte[] 數組。

? ? (2) 將新的byte[] 數組加載到PermGen 區(即加載新的byte[] 數組或替換原始類的字節碼)。

4. 使用較多的開源的字節碼增強API:

? ? ASM、javassist、BCEL、SERP、CGLib(基于ASM )

5. 加載字節數組的方式:

????1. 基于Java 的instrument API (接口ClassFileTransformer 的transform方法)

byte[] transform( ClassLoader loader, String className, Class?classBeingRedefined, ProtectionDomain ????protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException

????2. 通過指定的ClassLoader? 來完成

????FAQ: 這兩種加載字節數組的方式的區別?

附錄:

????ASM? 是一種修改字節碼本身的工具庫,它實現的抽象層次是很低的,幾乎接近于指令級別。例子中的操作都是基于指令和操作數的。

/**

* Visits a local variable instruction. A local variable instruction is an

* instruction that loads or stores the value of a local variable.

*

* @param opcode the opcode of the local variable instruction to be visited.

*? ? ? ? This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE,

*? ? ? ? LSTORE, FSTORE, DSTORE, ASTORE or RET.

* @param var the operand of the instruction to be visited. This operand is

*? ? ? ? the index of a local variable.

*/

void visitVarInsn(int opcode,int var);

LDC 指令將一個常量加載到操作數棧

/**

* Visits a LDC instruction.

*

* @param cst the constant to be loaded on the stack. This parameter must be

*? ? ? ? a non null {@link Integer}, a {@link Float}, a {@link Long}, a

*? ? ? ? {@link Double} a {@link String} (or a {@link Type} for

*? ? ? ? <tt>.class</tt>constants, for classes whose version is 49.0 or

*? ? ? ? more).

*/

void visitLdcInsn(Object cst);


/**

* Visits a field instruction. A field instruction is an instruction that

* loads or stores the value of a field of an object.

*

* @param opcode the opcode of the type instruction to be visited. This

*? ? ? ? opcode is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.

* @param owner the internal name of the field's owner class (see {@link

*? ? ? ? Type#getInternalName() getInternalName}).

* @param name the field's name.

* @param desc the field's descriptor (see {@link Type Type}).

*/

void visitFieldInsn(int opcode, String owner, String name, String desc);



/**

* Visits a method instruction. A method instruction is an instruction that

* invokes a method.

*

* @param opcode the opcode of the type instruction to be visited. This

*? ? ? ? opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC,

*? ? ? ? INVOKEINTERFACE or INVOKEDYNAMIC.

* @param owner the internal name of the method's owner class (see {@link

*? ? ? ? Type#getInternalName() getInternalName})

*? ? ? ? or {@link org.objectweb.asm.Opcodes#INVOKEDYNAMIC_OWNER}.

* @param name the method's name.

* @param desc the method's descriptor (see {@link Type Type}).

*/

void visitMethodInsn(int opcode, String owner, String name, String desc);


?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時,會觸發此異常。 O...
    我想起個好名字閱讀 5,429評論 0 9
  • Overview The ccxt library is a collection of available cr...
    郭蟈兒蟈兒閱讀 3,799評論 0 1
  • 到葡萄酒學院去學習釀酒,把葡萄變成酒的過程研究透,我們便有可能學會如何釀造一款好酒。但若想釀造出偉大的酒,則以下五...
    酒公子閱讀 291評論 0 0
  • 你在哪里 讓我千萬次尋找 懷念你的味道 你的音容笑貌 媽媽說 你在孩子身上的一針一線里 老師說 你在浩瀚的知識里 ...
    絲雨飄飛閱讀 148評論 0 1