代理模式(結合SpringAop底層實現)

Proxy代理模式

代理模式基本概念:爲其他對象提供一個代理來控制這個的訪問。

主要解決的問題:直接訪問對象時所帶來的問題。

代理類: 負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理

舉個栗子(=.=)

開始接觸spring框架的時候,必然的要去了解 IOC 和 AOP,其中AOP的底層實現原理就是動態代理。以此爲切入點,通過對AOP底層實現的理解,初識代理模式。

1、靜態代理實現AOP,首先來一波簡單代碼①

//目標對象的接口
public interface IWorkDao {
    void work();
}

//實現類
public class WorkDaoImpl implements IWorkDao {
    @Override
    public void work() {
        System.out.println("這裏是目標對象WorkDao的實現類");
    }
}

//增強類:一般給類方法添加事務控制或者性能檢測
public class TransactionManager {

    public void beginTransation(){
        System.out.println("start...");
    }

        //切割線------
        //...業務邏輯代碼
        //切割線------

       public void endTransation(){
        System.out.println("over...");
    }
}

目標對象增加的過程產生代理類

//代理對象持有被代理對象的一個接口public class WorkDaoProxy implements IWorkDao {    //主角:目標對象    IWorkDao workDao;    //配角:增強對象    TransactionManager tx;    //來一個構造器    public WorkDaoProxy(IWorkDao workDao, TransactionManager tx) {        this.workDao = workDao;        this.tx = tx;    }    //將增強添加到目標對象(織入)    @Override    public void work() {        tx.beginTransation();//非業務代碼        workDao.work(); //業務代碼        tx.endTransation();//非業務代碼,橫向切割體現出來了有木有    }}

//測試類
public class Test {
    public static void main(String[] args) {
        //目標對象
        IWorkDao workDao = new WorkDaoImpl();

        //增強
        TransactionManager tx = new TransactionManager();

        //代理對象
        WorkDaoProxy workDaoProxy = new WorkDaoProxy(workDao,tx);

        //代理對象調用目標方法
        workDaoProxy.work();
    }
}

這裏存在一個問題,要是我創建其他的目標對象接口比如ISleepDao或者修改當前類方法名,這不又得重新創建一個代理類或者修改?好麻煩有木有,所以就有以下方案:

2、基於jdk動態代理實現AOP(基於InvocationHandler接口模式),代碼①省略

//代理類
public class ProxyHandle implements InvocationHandler {
    //目標對象(不用知道具體的目標對象是誰,好神祕)
    Object target;

    //增強
    TransactionManager tx;

    //構造器(用於實例化handle)
    public ProxyHandle(Object target, TransactionManager tx) {
        this.target = target;
        this.tx = tx;
    }

    /**
    * 織入
    * @param proxy 
    * @param method 
    * @param args 參數列表
    * @return
    * @throws Throwable
    */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        tx.beginTransation();
        Object obj = method.invoke(target, args);
        tx.endTransation();
    return obj;
    }
}

//測試類
public class Test {
    public static void main(String[] args) {
    //目標對象
    IWorkDao workDao = new WorkDaoImpl();

    //增強
    TransactionManager tx = new TransactionManager();

    //獲得handle(構造器開闢內存空間用於存放目標對象和增強對象)
    ProxyHandle handle = new ProxyHandle(workDao,tx);

     //生成代理對象(傳入handle,利用反射獲得目標對象和增強)
    IWorkDao workDaoProxy = (IWorkDao) Proxy.newProxyInstance(workDao.getClass().getClassLoader(),                             workDao.getClass().getInterfaces(), handle);

    //代理對象調用目標方法
    workDaoProxy.work();
    }
}

解決了每創建一個目標對象必須創建一個代理類的問題,JDK中的動態代理是通過反射類Proxy以及InvocationHandler回調接口實現的,但是,JDK中所要進行動態代理的類必須要實現一個接口(如上面的:Object target 的接口),也就是說只能對該類所實現接口中定義的方法進行代理,這在實際編程中具有一定的侷限性,而且使用反射的效率也並不是很高。

3、基於cglib動態代理實現AOP,首先要導入cglib的jar包,繼續代碼①省略

    //代理類
    public class CglibDynInterceptor implements MethodInterceptor{
    //要代理的原始對象(拋棄你了)
    //private Object object;

    private Enhancer enhancer = new Enhancer();
    private TransactionManager tx;

    public CglibDynInterceptor(TransactionManager tx) {
    this.tx = tx;
}

    //創建子類
    public Object getProxy(Class cls){
    enhancer.setSuperclass(cls); //設置代理對象
    enhancer.setCallback(this); //回調MethodInterceptor接口方法攔截(類似於JDK中的            InvocationHandler接口)
    //通過字節碼技術動態創建子類
    return enhancer.create();
}

    /**
     * object:由CGLib動態生成的代理類實例
    * method:增強方法引用
    * args:參數值列表
    * methodProxy:生成的代理類對方法的代理引用
    */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy)
    throws Throwable {
     tx.beginTransation();
     //攔截父類方法(調用代理類實例上的proxy方法的父類方法)
     Object result = methodProxy.invokeSuper(object, args);
     tx.endTransation();
     return result;
    }
}

    //測試類 
    public class Test {
    public static void main(String[] args) {
    //增強
    TransactionManager tx = new TransactionManager();
    //創建代理類
    CglibDynInterceptor proxy = new CglibDynInterceptor(tx);
    //通過反射創建代理對象(子類)
    IWorkDao workDaoProxy = (IWorkDao) proxy.getProxy(IWorkDao.class);
    workDaoProxy.work();
    }
}

使用CGLib實現動態代理,完全不受代理類必須實現接口的限制,而且CGLib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,比使用Java反射效率要高。唯一需要注意的是,CGLib不能對聲明爲final的方法進行代理,因爲CGLib原理是動態生成被代理類的子類。

Enhancer允許爲非接口類型創建一個Java代理。Enhancer動態創建了給定類型的子類但是攔截了所有的方法。和Proxy不一樣的是,不管是接口還是類他都能正常工作(解決jdk動態代理中每創建一個代理類必須要實現接口)

另外:Callback接口是一個空接口,沒有任何契約方法,它只表示這是一個回調。

以上是個人結合SpringAop底層實現原理去理解代理模式,不足之處還請諒解~

 

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