jdk動態代理和cglib代理demo及總結

jdk動態代理和cglib代理技術在框架中使用非常頻繁,spring框架的AOP技術就使用二者代理技術進行切面編程,通過了解二者的代理機制來對Aop開發更深的理解。在這我分別對兩者代理技術分別做出演示!


jdk動態代理

這裏寫圖片描述
使用jdk動態代理只需要有jdk環境即可,是基於接口的代理技術,因此目標對象必須實現一個接口。
接口類UserService

package com.it.jdkProxy;

public interface UserService {
    void find();
    void get();
    void udpate();
    void delete();
}

目標對象UserServiceImpl

public class UserServiceImpl implements UserService {

    @Override
    public void find() {
        System.out.println("查詢用戶");
    }
    @Override
    public void get() {
        System.out.println("保存用戶");
    }
    @Override
    public void udpate() {
        System.out.println("更新用戶");
    }
    @Override
    public void delete() {
        System.out.println("刪除用戶");
    }
    private void prov(){
        System.out.println("測試private修飾");
    }
    protected void prot(){
        System.out.println("測試protected修飾");
    }
}

代理類UserServiceProxyFactory

package com.itcast.jdkProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class UserServiceProxyFactory implements InvocationHandler{
    private UserServiceImpl target;
    //通過構造傳入目標對象
    public UserServiceProxyFactory(UserServiceImpl target) {
        super();
        this.target = target;
    }
    //獲取動態代理對象
    public UserService getProxyUserService(){
        return (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }
    //代理對象的增強方法(核心方法)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //預處理
        System.out.println("開啓事務");
        //執行目標對象的方法(對所有public方法)
        Object invoke = method.invoke(target, args);
        //後處理
        System.out.println("提交事務");
        return invoke;
    }
}

測試類TestJdkProxy

package com.itcast.jdkProxy;

import org.junit.Test;

public class TestJdkProxy {
    @Test
    public void test(){
        //創建目標對象
        UserServiceImpl target = new UserServiceImpl();

        long currentTimeMillis1 = System.currentTimeMillis();
        //創建代理工廠
        UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(target);
        //得到代理對象
        UserService proxyUserService = proxyFactory.getProxyUserService();
        long currentTimeMillis2 = System.currentTimeMillis();
        //測試增強方法
        proxyUserService.find();
        proxyUserService.delete();
        proxyUserService.get();
        proxyUserService.udpate();
        System.out.println(currentTimeMillis2-currentTimeMillis1);
    }
}

測試結果
這裏寫圖片描述

cglib代理

cglib代理是基於繼承的代理技術,目標對象必須繼承某個類,所以目標類不應該被final修飾
需要導包
這裏寫圖片描述
目標對象UserServiceImpl(與jdk演示的目標對象時同一個)

代理類UserServiceImplProxyFactory

package com.itcast.cglibProxy;

import java.lang.reflect.Method;

import com.itcast.jdkProxy.UserServiceImpl;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class UserServiceImplProxyFactory implements MethodInterceptor{
    //持有要增強的對象
    private UserServiceImpl target;
    //持有增強器(手動創建)
    private Enhancer enhancer = new Enhancer(); 
    //代理對象的get方法
    public UserServiceImpl getProxy(UserServiceImpl target){
        //參數傳入要增強的對象
        this.target = target;
        //設置父類
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        //通過字節碼技術創建實例
        return (UserServiceImpl) enhancer.create();
    }
    /**
     * 所有方法都會被這個方法攔截。該類實現了創建子類的方法與代理的方法。
     * getProxy方法用過參數傳入父類的字節碼,用過擴展
     * 父類的class來創建代理對象。intercapter方法攔截所有目標類方法的調用,
     * obj代表目標類的實例,method爲目標類方法的放射對象
     * ,args爲方法的動態參數,proxy爲代理類實例
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] arg , MethodProxy methodProxy) 
            throws Throwable {
        System.out.println("cglib實現事務開始");
        Object result = methodProxy.invokeSuper(obj, arg);
        System.out.println("cglib實現事務提交!");

        return result;
    }

}

測試類TestCglibProxy

package com.itcast.cglibProxy;

import java.awt.SystemColor;
import org.junit.Test;
import com.itcast.jdkProxy.UserServiceImpl;

public class TestCglibProxy {
    @Test
    public void test(){
        //創建代理類對象
        UserServiceImplProxyFactory proxyFactory = new UserServiceImplProxyFactory();
        //得到子類實例

        long currentTimeMillis1 = System.currentTimeMillis();
        UserServiceImpl proxy = proxyFactory.getProxy(new UserServiceImpl());
        long currentTimeMillis2 = System.currentTimeMillis();
        //測試增強類的方法
        proxy.find();
        proxy.delete();
        proxy.get();
        proxy.udpate();
        //查看對象創建耗費的時間
        System.out.println("創建對象耗費時間:"+(currentTimeMillis2-currentTimeMillis1));
    }
}

測試結果:
這裏寫圖片描述
總結:
兩者的代理方式有區別.
一是jdk代理的目標對象需要實現一個接口,對pojo類沒有實現任何接口是不能被代理的,cglib代理需要的目標對象需要繼承一個父類,這個條件對於任何類來說都是可以被代理的,因爲所有類的父類都是Object類。
二是jdk動態代理創建代理對象耗費時間非常短,大家可以從測試結果上看出,相比較cglib代理很節省時間資源。所以在創鍵多例對象的代理對象時應該用jdk代理,cglib代理可以用在單例的代理對象創建。
三是動態代理只能對public修飾的方法進行調用,測試中分別寫了protected和private方法,並不能調用。

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