1. 程式人生 > >JDK的Proxy動態代理模式和CGLIB動態代理模式的區別和共同點

JDK的Proxy動態代理模式和CGLIB動態代理模式的區別和共同點

首先我們來談談聯眾代理模式的不同之處:

《1》代理類不同點:

(1)Proxy的代理類的建立是通過工具類或者工廠類自動建立的,

   我們只需要呼叫Proxy.newProxyInstance(Loader,interfaces,h);正確的傳入相應的引數,就可以得到餓哦們想要的目標類的代理類,這裡對這三個引數做一下簡單的介紹:Loader是目標類的類載入器,Interfaces是目標類實現的所有介面,h,是委託類物件。程式碼如下:

//動態生成代理物件
  ISomeService someServiceImpl = (ISomeService) Proxy.newProxyInstance(
    //目標類的類載入器 、

target.getClass().getClassLoader(),

    //目標類實現的所有介面
    target.getClass().getInterfaces(),
    
    //代理類的委託物件
    new ServiceProxyEntrust(target));

(1)Cglib的代理模式中,並沒有提供現成的工具或者工廠 類讓我們直接得到代理類,需要我們程式設計師手工定義類和方法來建立我們所需要的代理類,一般我個人喜歡把代理類的名字定義成“cglibProxy”,方法簽名定義成“newProxyInstance“,

CglibProxy.newProxyInstance(target.getClass(),mi);

target是我們的目標類,mi是我們的委託類物件。我們手工定義的工廠類的需要實現這個newProxyInstance()方法,並且在這個方法的內部,我們需要藉助增強器Enhancer來為我們的代理類指定目標類,並且讓委託類和目標類發生聯絡,具體的程式碼實現如下:

package com.abc.utils;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;//手工編寫的工具類,用於建立我們的代理物件
public class CglibProxy {
 
 //建立代理物件的過程中,我們需要藉助一個類
 //target:是我們的目標類
 //mi:是我們的委託類物件
 public static Object newProxyInstance(Class<?> target, MethodInterceptor mi) {
  //增強器
  Enhancer enhancer = new Enhancer();
  
  //指定父類,即指定目標類
  enhancer.setSuperclass(target);
  
  //指定回撥物件,即指定代理類
  //把目標類和委託類聯絡在了一起
  enhancer.setCallback(mi);
  
  //建立並且返回代理物件
  return enhancer.create();
 }}

通過這種方法,Cglib也可以一般性的建立代理類,但是我們之前說過,我們需要個性化的增強目標類,所以我們還應該讓這個目標類變得不一般,這就涉及到我們要說的第二點的不同,

《2》委託類的不同

(2)Proxy 的委託類需要實現InvocationHandler介面,該介面只有一個方法,我們需要重寫這個方法,

publci Object invoke(Object proxy,Method method,Object[] args);該方法的功能就是通過植入交叉邏輯程式碼。來達到個性化增強目標類的目的。(proxy是代理物件,method,是目標方法,args是目標方法的引數)程式碼如下:

/**
  * proxy:代理物件
  * method:目標方法
  * args:目標方法的引數
  */
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //植入交叉邏輯
  SystemUtil.doTx();
  //通過反射執行目標方法
  Object result = method.invoke(target, args);
  //植入交叉邏輯
  SystemUtil.doLog();
  return result;
 }

(2)Cglib的委託類需要實現的介面是MethodInterceptor,然後需要重寫該介面中的intercept() 方法,程式碼如下:

/**
  * obj:代理物件
  * method:目標方法
  * args:目標方法的引數
  * proxy:目標方法的代理物件
  */
 
 @Override
 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  //植入交叉邏輯
  SystemUtil.doTx();
  //通過反射執行目標方法
  Object result = method.invoke(target, args);
  //植入交叉邏輯
  SystemUtil.doLog();
  return result;

==================================================

小結:二者的不同之處在於

(1)Proxy的代理類是有工具類或者工廠類動態的生成(我們只需要呼叫相應的方法,然後正確的傳入引數即可,具體的生成過程可以通過debug模式檢視)

Cglib是沒有提供相應的工具類,需要程式設計師手工編寫,

(2)二者的委託類實現的介面不同,所以重寫的的介面也不同

(3)Proxy 動態代理要求目標類必須是要實現介面的類,而Cglib的目標類可以不用實現介面(當然了實現了介面的目標類也同樣可以適用,用法和沒有實現介面的類似),但是Cglib的目標類是不能被final所修飾的,且必須提供無參的構造器(因為Cglib的代理類其實是目標類的子類)

============================

相同點:

(1)二者都可以在不修改目標類的原始碼的情況下,達到個性化增強目標類的業務邏輯功能的目的。

(2)二者的委託類雖然實現的介面和方法不同,但是這兩個重寫的方法的功能相同,都是通過在目標方法的前後執行交叉程式碼邏輯(或者是系統及服務)來達到增加目標方法的作用。