ASM(初探使用)

ASM

背景

寫文章特別喜歡寫背景,感覺如果不寫背景就沒法回憶出來當時為什么要搞這個東西。好了,因為之前參與的一個項目的故障演練模塊覺得做的只是基于spring的Bean的代理做的,這樣對業(yè)務的侵入性比較強,如果業(yè)務沒有依賴于spring腫么辦呢?現(xiàn)在我們來看看ASM是怎么做的

ASM可以干什么

大名鼎鼎的CGLIB其實底層就是ASM。通過ASM的字節(jié)碼操作,可以動態(tài)創(chuàng)建新的類型,可以為類增加新的功能呢。雖然可以使用CGLIB這些高級的庫也可以完成大量的工作,但是如果直接使用ASM還是有很多好處的,例如ASM的性能是最好的,靈活度是最好的,功能也是最為強大的,可以將操作粒度控制到每一條指令。

簡單的進行字節(jié)碼織入操作

例如我們只有一個簡單的Account類,該類也只有一個方法operation方法。

public class Account {
    public void operation() {
        System.out.println("operation ...");
    }
}

現(xiàn)在我們要在這個操作之前進行一定的驗證,例如加入一些檢查權(quán)限的操作checkSecurity()。我們將添加一個名稱為SecurityChecker的類。這個類中的方法可以幫助我們進行一些權(quán)限校驗。

public class SecurityChecker {
    public static boolean checkSecurity() {
        System.out.println("SecurityChecker.checkSecurity ...");
        if ((System.currentTimeMillis() & 0x1) == 0) {
            return false;
        } else {
            return true;
        }
    }
}

我們在不修改原來Account的代碼的前提下,如何增加校驗操作呢?我們可以直接修改類的字節(jié)碼進行代碼織入操作,從而改變Account代碼的執(zhí)行狀態(tài)。

我們先看一下單獨運行Account類的執(zhí)行效果把~

image.png

可以看到只是打印出來了operation ...

進行改寫字節(jié)碼

通過如下代碼我們可以將代碼的字節(jié)碼進行修改,并且覆蓋掉原來的編譯好的字節(jié)碼,從而改變類的執(zhí)行狀態(tài)。

首先我們需要幾個類對象,第一個

  • 負責Class改寫的適配器類AddSecurityCheckClassAdapter繼承自ClassVisitor

  • 負責Method改寫的適配器類AddSecurityCheckMethodAdapter繼承自MethodVisitor

  • 負責調(diào)用Adapter的SecurityWeaveGeneratior

AddSecurityCheckClassAdapter

負責修改類文件中的字節(jié)碼

public class AddSecurityCheckClassAdapter extends ClassVisitor {

    public AddSecurityCheckClassAdapter(ClassVisitor classVisitor) {
        super(Opcodes.ASM5, classVisitor);
    }

    @Override
    public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings) {


        MethodVisitor mv = super.visitMethod(i, s, s1, s2, strings);

        MethodVisitor wrappedMv = mv;

        if (mv != null){
            if (s.equals("operation")){
                wrappedMv = new AddSecurityCheckMethodAdapter(mv);
            }
        }
        return wrappedMv;
    }
}

AddSecurityCheckMethodAdapter

負責修改某個method中的字節(jié)碼

public class AddSecurityCheckMethodAdapter extends MethodVisitor {
    public AddSecurityCheckMethodAdapter(MethodVisitor mv) {
        super(Opcodes.ASM5, mv);
    }

    @Override
    public void visitCode() {
        Label continueLabel = new Label();
        visitMethodInsn(Opcodes.INVOKESTATIC, "com/wsqandgy/asm/SecurityChecker", "checkSecurity", "()Z");
        visitJumpInsn(Opcodes.IFNE, continueLabel);
        visitInsn(Opcodes.RETURN);
        visitLabel(continueLabel);
        super.visitCode();
    }
}

SecurityWeaveGeneratior

讀取類信息,進行字節(jié)碼織入

public class SecurityWeaveGeneratior {

    public static void main(String[] args) throws Exception {
        String className = Account.class.getName();
        ClassReader classReader = new ClassReader(className);
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
        AddSecurityCheckClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);
        classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
        byte[] data = cw.toByteArray();
        File file = new File("/Users/gongyan/Documents/home_code/tools/apache/target/classes/" + className.replaceAll("\\.", "/") + ".class");
        if (file.exists()){
            System.out.println("exists");
        }
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        fileOutputStream.write(data);
        fileOutputStream.close();
    }
}

運行結(jié)果

安全檢查

還是運行原來的main方法,自動加入了檢查安全的操作。

對比一下前后的字節(jié)碼

前:


后:


對比前后,明顯可以看到在字節(jié)碼中增加了我們操作ASM寫入的相關字節(jié)碼。

寫在最后,最近生病是在身體乏力,寫的文章自己認為也只講了簡單的如何使用后面再好好補補,這個地方會和前面的服務保護有一定的串聯(lián)!請多多期待!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 前言 很早之前就寫過面向切面的編程思想,主要學習了AOP的思想(參考:AOP簡介)以及使用 AspectJ 實現(xiàn)簡...
    Whyn閱讀 11,166評論 4 40
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,203評論 8 265
  • title: Android AOP之字節(jié)碼插樁author: 陶超description: 實現(xiàn)數(shù)據(jù)收集SDK時...
    陶菜菜閱讀 38,684評論 40 182
  • 為毛ins的列表的視頻默認是關聲音的,但自動播放? 自動播放是因為這是個沒有詳情的列表,或者說列表即詳情,所有瀏覽...
    DanisUX閱讀 1,323評論 8 1
  • 對于試水自由市場,這些球員幾乎都是希望追逐總冠軍戒指,更多的上場時間,球權(quán)或是戰(zhàn)術比重,當然,還有大合同。 但問題...
    zoneball閱讀 277評論 0 0

友情鏈接更多精彩內(nèi)容