1. 程式人生 > 實用技巧 >位元組碼增強-learnning

位元組碼增強-learnning

jvm載入java的過程主要是:

編寫java檔案-》進行java檔案的編譯-》生成.class位元組碼檔案-》jvm通過類載入器去載入生成的二進位制檔案

java編譯器將原始碼檔案編譯稱為二進位制的.class檔案

為什麼要進行位元組碼增強操作?

不想修改原始碼,但是又想加入新功能,讓程式按照我們的預期去執行,可以通過編譯過程和載入過程中去做

相應的操作,

簡單來講就是:將生成的.class檔案修改或者替換稱為我們需要的目標.class檔案。

需要依賴第三方的工具去實現位元組碼增強

這裡使用javassist實現;

步驟:

/**
 * 步驟1:編寫你最初的業務類,實現業務功能
 
*/ public class BaseService { public void basePrint(Map map){ System.out.println(map.toString()); } }

/**
 * 步驟2:編寫你需要的對業務類進行增強的類或者內容
 */
public class ExBaseService {
    public static  void exPrint(Map map){
        System.out.println("exbaseService增強的功能==需要增強的方法之前");
    }

    public
static void exPrintL(Map map){ System.out.println("exbaseService增強的功能==需要增強的方法之後"); } }

/**
 * 步驟3:編寫增強的工具類,之後直接呼叫後再使用原來的業務類方法就實現增強了
 * ClassPool其實是一張儲存了CtClass資訊的雜湊表,key=類的全限定類名,value=類名對應的CtClass物件。
 *          當需要對某個類修改的時候,通過方法getCtClass(className)從classpool獲取到相應的CtClass
 * CtClass:編譯時的類資訊,一個class檔案在程式碼中的抽象表現形式,全限定類名可以獲取CtClass物件,用於表示這個類檔案
 * CtMethod: 類中的方法 定義或修改
 * CtField:  類中的屬性 定義或修改
 *
 * javassist 增強程式碼片段是字串編寫,以$開頭用於表示方法或建構函式引數或方法返回值
 
*/ public class ServiceUtils { public static void done() throws NotFoundException, CannotCompileException { ClassPool classPool = ClassPool.getDefault();//獲取預設的類池 //通過全限定類名從類池獲取對應需要增強的類 CtClass base = classPool.getOrNull("com.quan.security.intecepter.BaseService"); if (base == null){ System.out.println("can not found"); return; } //通過方法getDeclaredMethod和類中需要增強的方法名字得到CtMethod型別的方法抽象 CtMethod basemethod = base.getDeclaredMethod("basePrint"); //組合增強字串,使用$1獲取方法的引數。 StringBuffer sbf = new StringBuffer(); sbf.append("{"); sbf.append("com.quan.security.intecepter.ExBaseService.exPrint($1);"); sbf.append("}"); //進行增強,呼叫之前增強 basemethod.insertBefore(sbf.toString()); StringBuffer sbf2 = new StringBuffer(); sbf2.append("{"); sbf2.append("com.quan.security.intecepter.ExBaseService.exPrintL($1);"); sbf2.append("}"); //進行增強,呼叫需要增強方法之後增強 basemethod.insertAfter(sbf2.toString()); //替換增強後的位元組碼 base.toClass(); } }

public class IntecepterTest {
    /**
     * 呼叫增強工具類,使最初的業務類進行增強,
     * 隨後呼叫業務類,檢視是否增強
     * @param args
     */
    public static void main(String[] args)  {
        try {
            ServiceUtils.done();
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        }
        BaseService baseService = new BaseService();
        Map<String,String> map1 = new HashMap<>();
        map1.put("name","quan");
        baseService.basePrint(map1);
    }
}

結果:

exbaseService增強的功能==需要增強的方法之前
{name=quan}
exbaseService增強的功能==需要增強的方法之後