JDK動態代理java
利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。
CGlib動態代理數組
利用ASM(開源的Java字節碼編輯庫,操做字節碼)開源包,將代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理。
區別框架
JDK代理只能對實現接口的類生成代理;CGlib是針對類實現代理,對指定的類生成一個子類,並覆蓋其中的方法,這種經過繼承類的實現方式,不能代理final修飾的類。
目標接口類ide
/** * 目標接口類 */ public interface UserManager { void addUser(String username, String password); void delUser(String username); }
接口實現類測試
/** * 動態代理: * 1. 特色:字節碼隨用隨建立,隨用隨加載 * 2. 做用:不修改源碼的基礎上對方法加強 * 3. 分類: * 1)基於接口的動態代理 * 1. 基於接口的動態代理: * 1)涉及的類:Proxy * 2)提供者:JDK官方 * 3)如何建立代理對象: * 使用Proxy類中的newProxyInstance方法 * 4)建立代理對象的要求 * 被代理類最少實現一個接口,若是沒有則不能使用 * 5)newProxyInstance方法的參數: * ClassLoader:類加載器,它是用於加載代理對象字節碼的。和被代理對象使用相同的類加載器。固定寫法。 * Class[]:字節碼數組,它是用於讓代理對象和被代理對象有相同方法。固定寫法。 * InvocationHandler:用於提供加強的代碼,它是讓咱們寫如何代理。咱們通常都是些一個該接口的實現類,一般狀況下都是匿名內部類 * 2)基於子類的動態代理 */ public class JDKProxy implements InvocationHandler { // 用於指向被代理對象 private Object targetObject; public Object newProxy(Object targetObject) { // 將被代理對象傳入進行代理 this.targetObject = targetObject; // 返回代理對象 return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(),this); } /** * 被代理對象的任何方法執行時,都會被invoke方法替換,即:代理對象執行被代理對象中的任何方法時,實際上執行的時當前的invoke方法 * @param proxy(代理對象的引用) * @param method(當前執行的方法) * @param args(當前執行方法所需的參數) * @return(和被代理對象方法有相同的返回值) * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在原來的方法上增長了日誌打印功能,加強代碼 printLog(); Object ret = null; // 調用invoke方法(即執行了代理對象調用被調用對象中的某個方法) ret = method.invoke(targetObject, args); return ret; } /** * 模擬日誌打印 */ private void printLog() { System.out.println("日誌打印:printLog()"); } }
測試類this
public class TestJDKProxy { public static void main(String[] args) { UserManager userManager = new UserManagerImpl(); JDKProxy jdkProxy = new JDKProxy(); UserManager userManagerProxy = (UserManager)jdkProxy.newProxy(userManager); System.out.println("--------------------沒有使用加強過的方法--------------------"); userManager.addUser("root","root"); userManager.delUser("root"); System.out.println("--------------------使用代理對象加強過的方法--------------------"); userManagerProxy.addUser("scott","tiger"); userManagerProxy.delUser("scott"); } }
測試結果.net
--------------------沒有使用加強過的方法-------------------- 調用了UserManagerImpl.addUser()方法! 調用了UserManagerImpl.delUser()方法! --------------------使用代理對象加強過的方法-------------------- 日誌打印:printLog() 調用了UserManagerImpl.addUser()方法! 日誌打印:printLog() 調用了UserManagerImpl.delUser()方法!
/** * 動態代理: * 1. 特色:字節碼隨用隨建立,隨用隨加載 * 2. 做用:不修改源碼的基礎上對方法加強 * 3. 分類: * 1)基於接口的動態代理 * 2)基於子類的動態代理 * 1. 基於子類的動態代理: * 1)涉及的類:Enhancer * 2)提供者:第三方cglib庫 * 3)如何建立代理對象: * 使用Enhancer類中的create方法 * 4)建立代理對象的要求 * 被代理類不能是最終類 * 5)create方法的參數: * Class:字節碼,它是用於指定被代理對象的字節碼。固定寫法。 * Callback():用於提供加強的代碼,它是讓咱們寫如何代理。咱們通常都是些一個該接口的實現類。固定寫法。 */ public class CGLibProxy implements MethodInterceptor { // 用於指向被代理對象 private Object targetObject; // 用於建立代理對象 public Object createProxy(Object targetObject) { this.targetObject = targetObject; return new Enhancer().create(this.targetObject.getClass(),this); } /** * * @param proxy(代理對象的引用) * @param method(當前執行的方法) * @param args(當前執行方法所需的參數) * @param methodProxy(當前執行方法的代理對象) * @return(和被代理對象方法有相同的返回值) * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object ret = null; // 過濾方法 if ("addUser".equals(method.getName())) { // 日誌打印 printLog(); } ret = method.invoke(targetObject, args); return ret; } /** * 模擬日誌打印 */ private void printLog() { System.out.println("日誌打印:printLog()"); } }
測試類代理
public class TestCGLibProxy { public static void main(String[] args) { CGLibProxy cgLibProxy = new CGLibProxy(); UserManager userManager = new UserManagerImpl(); UserManager cgLibProxyProxy = (UserManager)cgLibProxy.createProxy(userManager); System.out.println("--------------------沒有使用加強過的方法--------------------"); userManager.addUser("root","root"); userManager.delUser("root"); System.out.println("--------------------使用代理對象加強過的方法--------------------"); cgLibProxyProxy.addUser("scott","tiger"); cgLibProxyProxy.delUser("scott"); } }
測試結果日誌
--------------------沒有使用加強過的方法-------------------- 調用了UserManagerImpl.addUser()方法! 調用了UserManagerImpl.delUser()方法! --------------------使用代理對象加強過的方法-------------------- 日誌打印:printLog() 調用了UserManagerImpl.addUser()方法! 調用了UserManagerImpl.delUser()方法!
1)JDK代理使用的是反射機制實現aop的動態代理,CGLIB代理使用字節碼處理框架asm,經過修改字節碼生成子類。因此jdk動態代理的方式建立代理對象效率較高,執行效率較低,cglib建立效率較低,執行效率高;
2)JDK動態代理機制是委託機制,具體說動態實現接口類,在動態生成的實現類裏面委託hanlder去調用原始實現類方法,CGLIB則使用的繼承機制,具體說被代理類和代理類是繼承關係,因此代理類是能夠賦值給被代理類的,若是被代理類有接口,那麼代理類也能夠賦值給接口。code