JDK動態代理和CGLIB代理的區別


一、原理區別:

java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。

而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。

1、如果目標對象實現了接口,默認情況下會采用JDK的動態代理實現AOP 
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP 

3、如果目標對象沒有實現了接口,必須采用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

如何強制使用CGLIB實現AOP?
 (1)添加CGLIB庫,SPRING_HOME/cglib/*.jar
 (2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK動態代理和CGLIB字節碼生成的區別?
 (1)JDK動態代理只能對實現了接口的類生成代理,而不能針對類
 (2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
   因為是繼承,所以該類或方法最好不要聲明成final 

二、代碼實現

 

    package com.fy.spring.proxy;    
        
    public interface UserManager {    
        public void addUser(String id, String password);    
        public void delUser(String id);    
    }   


[html] view plain copy

    package com.fy.spring.proxy;    
        
    public class UserManagerImpl implements UserManager {    
        
        public void addUser(String id, String password) {    
            System.out.println(".: 掉用了UserManagerImpl.addUser()方法! ");    
        
        }    
        
        public void delUser(String id) {    
            System.out.println(".: 掉用了UserManagerImpl.delUser()方法! ");    
        
        }    
    }   

 

 JDK動態代理類

    package com.fy.spring.proxy;    
    import java.lang.reflect.InvocationHandler;    
    import java.lang.reflect.Method;    
    import java.lang.reflect.Proxy;    
    /**   
     *    
     * JDK動態代理類   
     *    
     *   
     */    
    public class JDKProxy implements InvocationHandler {    
        
        private Object targetObject;//需要代理的目標對象    
        
        public Object newProxy(Object targetObject) {//將目標對象傳入進行代理    
            this.targetObject = targetObject;     
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),    
                    targetObject.getClass().getInterfaces(), this);//返回代理對象    
        }    
        
        public Object invoke(Object proxy, Method method, Object[] args)//invoke方法    
                throws Throwable {    
            checkPopedom();//一般我們進行邏輯處理的函數比如這個地方是模擬檢查權限    
            Object ret = null;      // 設置方法的返回值    
            ret  = method.invoke(targetObject, args);       //調用invoke方法,ret存儲該方法的返回值    
            return ret;    
        }    
        
        private void checkPopedom() {//模擬檢查權限的例子    
            System.out.println(".:檢查權限  checkPopedom()!");    
        }    
    }    

 CGLIBProxy動態代理類

    package com.fy.spring.proxy;    
        
    import java.lang.reflect.Method;    
        
    import net.sf.cglib.proxy.Enhancer;    
    import net.sf.cglib.proxy.MethodInterceptor;    
    import net.sf.cglib.proxy.MethodProxy;    
        
    /**   
     * CGLibProxy動態代理類的實例   
     *     
     *    
     */    
    public class CGLibProxy implements MethodInterceptor {    
        
        private Object targetObject;// CGLib需要代理的目標對象    
        
        public Object createProxyObject(Object obj) {    
            this.targetObject = obj;    
            Enhancer enhancer = new Enhancer();    
            enhancer.setSuperclass(obj.getClass());    
            enhancer.setCallback(this);    
            Object proxyObj = enhancer.create();    
            return proxyObj;// 返回代理對象    
        }    
        
        public Object intercept(Object proxy, Method method, Object[] args,    
                MethodProxy methodProxy) throws Throwable {    
            Object obj = null;    
            if ("addUser".equals(method.getName())) {// 過濾方法    
                checkPopedom();// 檢查權限    
            }    
            obj = method.invoke(targetObject, args);    
            return obj;    
        }    
        
        private void checkPopedom() {    
            System.out.println(".:檢查權限  checkPopedom()!");    
        }    
    }    

 測試類

    public class Client {    
        
        public static void main(String[] args) {    
        
            UserManager userManager = (UserManager) new CGLibProxy()    
                    .createProxyObject(new UserManagerImpl());    
            System.out.println("-----------CGLibProxy-------------");    
            userManager.addUser("tom", "root");    
            System.out.println("-----------JDKProxy-------------");    
            JDKProxy jdkPrpxy = new JDKProxy();    
            UserManager userManagerJDK = (UserManager) jdkPrpxy    
                    .newProxy(new UserManagerImpl());    
            userManagerJDK.addUser("tom", "root");    
        }    
        
    }   

 運行結果

    -----------CGLibProxy-------------    
    檢查權限  checkPopedom()!    
    掉用了UserManagerImpl.addUser()方法!     
    -----------JDKProxy-------------    
    檢查權限  checkPopedom()!    
    掉用了UserManagerImpl.addUser()方法!  

 

JDK代理是不需要以來第三方的庫,只要要JDK環境就可以進行代理,它有幾個要求
* 實現InvocationHandler 
* 使用Proxy.newProxyInstance產生代理對象
* 被代理的對象必須要實現接口
CGLib 必須依賴於CGLib的類庫,但是它需要類來實現任何接口代理的是指定的類生成一個子類,覆蓋其中的方法,是一種繼承但是針對接口編程的環境下推薦使用JDK的代理
在Hibernate中的攔截器其實現考慮到不需要其他接口的條件Hibernate中的相關代理采用的是CGLib來執行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM