JDK代理和Cglib代理的區別

一、原理區別

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

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

JDK動態代理和CGLIB字節碼生成的區別?

(1)JDK動態代理只能對實現了接口的類生成代理,而不能針對類

(2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法

因爲是繼承,所以該類或方法最好不要聲明成final

二,代理實現

JDK動態代理

1.實現InvocationHandler

public class MyInvocationHandler implements InvocationHandler{

    /**
     * 要代理的目標對象
     */
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 執行方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法執行之前...");
        Object result = method.invoke(this.target,args);
        System.out.println("方法執行之後...");
        return result;
    }

    /**
     * 生成代理對象
     * @return
     */
    public Object getProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                this.target.getClass().getInterfaces(),this);
    }
}
2.提供接口

public interface Person{
    void makeFriend(String name);
}
3.子類實現接口

public class ZhangSan implements Person {
    @Override
    public void makeFriend(String name) {
        System.out.println("和"+name+"交了個朋友");
    }
}
4.測試類

public class ProxyTest {
    public static void main(String[] args) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(new ZhangSan());
        Person person = (Person) myInvocationHandler.getProxy();
        //System.out.println(person);
        person.makeFriend("林志玲");
    }
}
5.打印結果

方法執行之前...
和林志玲交了個朋友
方法執行之後...


CGLIB動態代理

1.提供目標類

public class XiaoMing {
    void sayHello(){
        System.out.println("hello everyone");
    }
}
2.生成代理類

public class CglibProxy implements MethodInterceptor {

    public Object getProxy(Class clazz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);//設置代理類的父類爲目標類
        enhancer.setCallback(this);//回調
        return enhancer.create();//生成代理類
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //生成代理類是子類,因此調用父類的方法
        Object obj = proxy.invokeSuper(o, args);
        return obj;
    }
}
3.測試
public class CglibTest {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        XiaoMing xiaoMing = (XiaoMing) cglibProxy.getProxy(XiaoMing.class);
        xiaoMing.sayHello();
    }
}
4.打印結果

hello everyone

三,總結

jdk代理
代理對象和目標對象實現了相同了接口,目標對象作爲代理對象的一個屬性在維護,此代理模式在使用時需要制定具體目標對象,並且只針對實現了接口的類生成代理
cglib代理
cglib代理是針對類實現代理,生成的是目標類的子類代理對象,覆蓋其所有方法,所以目標類或方法不能聲明成final的。如果目標對象實現了接口,可以強制使用CGLIB實現代理(添加CGLIB庫,並在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

cglib動態創建代理對象性能比jdk創建效率要高,對於單例對象,cglib更適合,不用頻繁創建對象;反之jdk代理更適合




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章