剛開始接觸java,總是聽到AOP技術也就是面向切面編程技術,一直很迷糊,它到底是什么,干什么用的,實現原理是什么。今天在這里做個小結。
首先介紹一下AOP技術的由來:
在我們的業務系統中,有時候需要用業務系統中的”某些代碼”去執行一些公共的動作,比如寫日志、數據庫連接管理、事務管理。那么這樣就需要我們在很多方法中添加重復代碼,這樣使得代碼重復率過高,也不好維護。那么我們想到的是要求每個Action都繼承框架提供好的BaseAction,然后實現excute方法來實現。不過,這樣的方式缺乏靈活性,那就是我們每個Action都需要寫一個類來完成,對於復雜的系統,就需要寫太多這樣的類,因此,我們期望有一種動態的方式來代理操作,於是動態代理機制就出現了,AOP技術其實也是字節碼增強技術,JVM提供的動態代理追根到底也是字節碼增強技術。
字節碼增強技術的實現原理:
字節碼增強技術的實現有兩種方式:
一種是通過創建原始類的一個子類,也就是動態創建的一個新的類繼承原始類。
二種是很暴力的方式,直接修改Class字節碼。
實現字節碼增強技術的步驟:
一是在內存中獲取原始的字節碼,通過一些開源的API修改它的byte[]數組,得到一個新的byte[]。
二將這個新的byte[]數組寫到PermGen區域,也就是加載新的byte[]替換原來的Class字節碼。
實現原理和簡介就介紹到這里,下面我們來個例子。
我們采用的開源api 為javaassit的API來實現字節碼增強技術。
我們構造一個Transformer方法,它需要實現接口ClassFileTransformer,並實現transform方法,代碼如下:
1、修改class字節碼
public class TestTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { System.out.println("load class:"+className); //判斷是否是需要我們切得目標類 if("/targetclass".equals(className)){ CtClass ctClass=ClassPool.getDefault().get(className.replace('/', '.')); //獲取需要切得目標方法 CtMethod ctMethod=ctClass.getDeclaredMethod("display1"); //插入需要在此之前執行的方法 ctMethod.insertBefore("name=\"XXXX\";"); //插入需要在display1之后執行的方法 ctMethod.insertAfter("System.out.println(value);"); return ctClass.toBytecode(); } // TODO Auto-generated method stub return null; } }
2、注冊到Instrumentation中,加載新的class字節碼
public class InstForTransformer{ public static void premain(String agentArgs,Instrumentation instP){ instP.addTransformer(new TestTransformer()); } }
如果注冊成功,那么在JVM加載用戶class是,就會調用對應的TestTransformer類的transform方法來獲得修改后的字節碼,達到修改字節碼的目的。發現很多java教程都沒有這方面的講解,那就我來彌補一下吧