位元組碼增強-learnning
阿新 • • 發佈:2020-08-20
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增強的功能==需要增強的方法之前"); } publicstatic 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增強的功能==需要增強的方法之後