溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java設(shè)計(jì)模式之代理模式原理及實(shí)現(xiàn)代碼分享

發(fā)布時(shí)間:2020-09-15 22:11:04 來(lái)源:腳本之家 閱讀:151 作者:BuleSky 欄目:編程語(yǔ)言

簡(jiǎn)介

Java編程的目標(biāo)是實(shí)現(xiàn)現(xiàn)實(shí)不能完成的,優(yōu)化現(xiàn)實(shí)能夠完成的,是一種虛擬技術(shù)。生活中的方方面面都可以虛擬到代碼中。代理模式所講的就是現(xiàn)實(shí)生活中的這么一個(gè)概念:中介

代理模式的定義:給某一個(gè)對(duì)象提供一個(gè)代理,并由代理對(duì)象控制對(duì)原對(duì)象的引用。

代理模式包含如下角色:

ISubject:抽象主題角色,是一個(gè)接口。該接口是對(duì)象和它的代理共用的接口。

RealSubject:真實(shí)主題角色,是實(shí)現(xiàn)抽象主題接口的類。

Proxy:代理角色,內(nèi)部含有對(duì)真實(shí)對(duì)象RealSubject的引用,從而可以操作真實(shí)對(duì)象。代理對(duì)象提供與真實(shí)對(duì)象相同的接口,以便在任何時(shí)刻都能代替真實(shí)對(duì)象。同時(shí),代理對(duì)象可以在執(zhí)行真實(shí)對(duì)象操作時(shí),附加其他的操作,相當(dāng)于對(duì)真實(shí)對(duì)象進(jìn)行封裝。

實(shí)現(xiàn)動(dòng)態(tài)代理的關(guān)鍵技術(shù)是反射。

靜態(tài)代理

代理模式有幾種,虛擬代理,計(jì)數(shù)代理,遠(yuǎn)程代理,動(dòng)態(tài)代理。主要分為兩類,靜態(tài)代理和動(dòng)態(tài)代理。靜態(tài)代理比較簡(jiǎn)單,是由程序員編寫(xiě)的代理類,并在程序運(yùn)行前就編譯好的,而不是由程序動(dòng)態(tài)產(chǎn)生代理類,這就是所謂的靜態(tài)。

考慮這樣的場(chǎng)景,管理員在網(wǎng)站上執(zhí)行操作,在生成操作結(jié)果的同時(shí)需要記錄操作日志,這是很常見(jiàn)的。此時(shí)就可以使用代理模式,代理模式可以通過(guò)聚合和繼承兩種方式實(shí)現(xiàn):

/**方式一:聚合式靜態(tài)代理
 * @author Goser  (mailto:goskalrie@163.com)
 * @Since 2016年9月7日
 */
//1.抽象主題接口
public interface Manager {
  void doSomething();
}
//2.真實(shí)主題類
public class Admin implements Manager {
  public void doSomething() {
    System.out.println("Admin do something.");
  }
}
//3.以聚合方式實(shí)現(xiàn)的代理主題
public class AdminPoly implements Manager{
  private Admin admin;
  
  public AdminPoly(Admin admin) {
    super();
    this.admin = admin;
  }
 
  public void doSomething() {
    System.out.println("Log:admin操作開(kāi)始");
    admin.doSomething();
    System.out.println("Log:admin操作結(jié)束");
  }
}
//4.測(cè)試代碼
    Admin admin = new Admin();
    Manager m = new AdminPoly(admin);
    m.doSomething();
//方式二:繼承式靜態(tài)代理
//與上面的方式僅代理類和測(cè)試代碼不同
//1.代理類
public class AdminProxy extends Admin {
  @Override
  public void doSomething() {
    System.out.println("Log:admin操作開(kāi)始");
    super.doSomething();
    System.out.println("Log:admin操作開(kāi)始");
  }
}
//2.測(cè)試代碼
    AdminProxy proxy = new AdminProxy();
    proxy.doSomething();

聚合實(shí)現(xiàn)方式中代理類聚合了被代理類,且代理類及被代理類都實(shí)現(xiàn)了同一個(gè)接口,可實(shí)現(xiàn)靈活多變。繼承式的實(shí)現(xiàn)方式則不夠靈活。

比如,在管理員操作的同時(shí)需要進(jìn)行權(quán)限的處理,操作內(nèi)容的日志記錄,操作后數(shù)據(jù)的變化三個(gè)功能。三個(gè)功能的排列組合有6種,也就是說(shuō)使用繼承要編寫(xiě)6個(gè)繼承了Admin的代理類,而使用聚合,僅需要針對(duì)權(quán)限的處理、日志記錄和數(shù)據(jù)變化三個(gè)功能編寫(xiě)代理類,在業(yè)務(wù)邏輯中根據(jù)具體需求改變代碼順序即可。

動(dòng)態(tài)代理

一般來(lái)說(shuō),對(duì)代理模式而言,一個(gè)主題類與一個(gè)代理類一一對(duì)應(yīng),這也是靜態(tài)代理模式的特點(diǎn)。

但是,也存在這樣的情況,有n各主題類,但是代理類中的“前處理、后處理”都是一樣的,僅調(diào)用主題不同。也就是說(shuō),多個(gè)主題類對(duì)應(yīng)一個(gè)代理類,共享“前處理,后處理”功能,動(dòng)態(tài)調(diào)用所需主題,大大減小了程序規(guī)模,這就是動(dòng)態(tài)代理模式的特點(diǎn)。

JDK動(dòng)態(tài)代理

實(shí)現(xiàn)

//1. 抽象主題
public interface Moveable {
  void move() throws Exception;
}
//2. 真實(shí)主題
public class Car implements Moveable {
  public void move() throws Exception {
    Thread.sleep(new Random().nextInt(1000));
    System.out.println("汽車行駛中…");
  }
}
//3.事務(wù)處理器
public class TimeHandler implements InvocationHandler {
  private Object target;
  public TimeHandler(Object target) {
    super();
    this.target = target;
  }
  /**
   * 參數(shù):
   *proxy 被代理的對(duì)象
   *method 被代理對(duì)象的方法
   *args 方法的參數(shù)
   * 返回:
   *Object 方法返回值
   */
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    long startTime = System.currentTimeMillis();
    System.out.println("汽車開(kāi)始行駛…");
    method.invoke(target, args);
    long stopTime = System.currentTimeMillis();
    System.out.println("汽車結(jié)束行駛…汽車行駛時(shí)間:" + (stopTime - startTime) + "毫秒!");
    return null;
  }
}
//測(cè)試類
public class Test {
  public static void main(String[] args) throws Exception{
    Car car = new Car();
    InvocationHandler h = new TimeHandler(car);
    Class<!--?--> cls = car.getClass();
    /**
     *loader 類加載器
     *interfaces 實(shí)現(xiàn)接口
     *h InvocationHandler
     */
    Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
    m.move();
  }
}

代碼講解:

在測(cè)試代碼中,Proxy.newProxyInstance()方法需要3個(gè)參數(shù):類加載器(要進(jìn)行代理的類)、被代理類實(shí)現(xiàn)的接口,事務(wù)處理器。所以先實(shí)例化Car,實(shí)例化InvocationHandler的子類TimeHandler,將各參數(shù)傳入Proxy的靜態(tài)方法newProxyInstance()即可獲得Car的代理類,前面的靜態(tài)代理,代理類是我們編寫(xiě)好的,而動(dòng)態(tài)代理則不需要我們?nèi)ゾ帉?xiě)代理類,是在程序中動(dòng)態(tài)生成的。

JDK動(dòng)態(tài)代理步驟

1.創(chuàng)建一個(gè)實(shí)現(xiàn)InvocationHandler接口的類,它必須實(shí)現(xiàn)invoke()方法

2.創(chuàng)建被代理的類及接口

3.調(diào)用Proxy的靜態(tài)方法,創(chuàng)建一個(gè)代理類

4.通過(guò)代理調(diào)用方法

而為什么要進(jìn)行如此操作,可以從Proxy和InvocationHandler的源碼中找打答案。對(duì)源碼不感興趣的可以將下面的源碼部分小節(jié)略過(guò)。

JDK動(dòng)態(tài)代理原理與源碼

newProxyInstance()方法的源碼:

public static Object newProxyInstance(ClassLoader loader,
                     Class<!--?-->[] interfaces,
                     InvocationHandler h)
    throws IllegalArgumentException{
    if (h == null) {
      throw new NullPointerException();
    }
    final Class<!--?-->[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
      checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    /*查找或生成指定的代理類*/
    Class<!--?--> cl = getProxyClass0(loader, intfs);
    /*用指定的調(diào)用處理程序調(diào)用它的構(gòu)造函數(shù).*/
    try {
    //獲得類的構(gòu)造函數(shù)
      final Constructor<!--?--> cons =cl.getConstructor(constructorParams);
      final InvocationHandler ih = h;
      if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
       //當(dāng)需要代理的類實(shí)現(xiàn)了一個(gè)非public的接口時(shí),因?yàn)檫@樣的接口需要特殊的權(quán)限,因此調(diào)用doPrivilege(native 修飾的方法)創(chuàng)建代理實(shí)例。
        return AccessController.doPrivileged(newPrivilegedAction<object>() {
          public Object run() {
            return newInstance(cons,ih);
          }
        });
      } else {
        return newInstance(cons,ih);
      }
    } catch (NoSuchMethodException e) {
      throw new InternalError(e.toString());
    }
}

可以看到,獲得代理類的代碼是

Classcl = getProxyClass0(loader,intfs);

并由此獲得代理類的構(gòu)造函數(shù),生成代理類的實(shí)例返回給該方法的調(diào)用者。

繼續(xù)跟進(jìn)getProxyClass0()方法:

/** 生成代理類。調(diào)用該方法前必須使用checkproxyaccess方法執(zhí)行權(quán)限檢查。*/
  private static Class<!--?--> getProxyClass0(ClassLoader loader,
                     Class<!--?-->... interfaces) {
  //檢查實(shí)現(xiàn)的接口數(shù),65535這個(gè)數(shù)字好特殊,端口數(shù)好像也是這個(gè),這個(gè)數(shù)字是由虛擬機(jī)所決定的,2^16-1個(gè)
  if (interfaces.length > 65535) {
      throw new IllegalArgumentException("interface limit exceeded");
    }
    // 如果代理類已經(jīng)通過(guò)實(shí)現(xiàn)給定接口的類加載器創(chuàng)建了,則返回緩存中的該類的副本;否則將通過(guò)ProxyClassFactory創(chuàng)建代理類
    return proxyClassCache.get(loader, interfaces);
}

還是沒(méi)有看到代理類是怎么生成的,只知道代理類是從proxyClassCache中取得的,這個(gè)變量是與緩存相關(guān)的一個(gè)對(duì)象,查看該變量的聲明與初始化:

private static final WeakCache<classloader,>[], Class<!--?-->>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());</classloader,>

可以發(fā)現(xiàn)proxyClassCache是個(gè)用來(lái)緩存代理類的類變量,大家知道類變量的特點(diǎn)是與類一一對(duì)應(yīng),在一個(gè)虛擬機(jī)中類只有一個(gè),對(duì)應(yīng)著在一個(gè)虛擬機(jī)中類變量也只有一個(gè),且在此處,在Proxy類被加載的時(shí)候就賦值了。在賦值操作的參數(shù)中有ProxyClassFactory()這么一個(gè)構(gòu)造函數(shù),這個(gè)是動(dòng)態(tài)代理中的關(guān)鍵:生成代理類的類文件字節(jié)碼。繼續(xù)跟進(jìn)去,找到代理類的生成之處了:

  /** 根據(jù)給定的類加載器和接口數(shù)組生成代理類的工廠類*/
  private static final class ProxyClassFactory
    implements BiFunction<classloader,class<?>[], Class<!--?-->>
  {
    // 所有代理類名稱的前綴
    private static final String proxyClassNamePrefix = "$Proxy";
 
    //用于生成唯一代理類名稱的下一個(gè)序號(hào)
    private static final AtomicLong nextUniqueNumber = new AtomicLong();
 
    @Override
    public Class<!--?--> apply(ClassLoader loader,Class<!--?-->[] interfaces) {
 
      Map<class<?>, Boolean>interfaceSet = new IdentityHashMap<>(interfaces.length);
      for (Class<!--?--> intf : interfaces) {
        /* 驗(yàn)證類加載器將此接口的名稱解析為實(shí)際對(duì)象的名稱。*/
        Class<!--?--> interfaceClass =null;
        try {
          interfaceClass = Class.forName(intf.getName(),false, loader);
        } catch (ClassNotFoundException e) {
        }
        if (interfaceClass != intf) {
          throw new IllegalArgumentException(
            intf + " is not visible from classloader");
        }
        /* 驗(yàn)證類對(duì)象確實(shí)是一個(gè)接口。*/
        if (!interfaceClass.isInterface()) {
          throw new IllegalArgumentException(
            interfaceClass.getName() + " is not an interface");
        }
        /*確保接口唯一*/
        if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
          throw new IllegalArgumentException(
            "repeated interface: " + interfaceClass.getName());
        }
      }
 
      String proxyPkg = null;   // 代理類的包名
 
      /*記錄非公開(kāi)代理接口的包,以便將代理類定義在同一個(gè)包中。確認(rèn)所有非公共代理接口都在同一個(gè)包中。*/
      for (Class<!--?--> intf : interfaces) {
        int flags = intf.getModifiers();
        if (!Modifier.isPublic(flags)) {
          String name =intf.getName();
          int n = name.lastIndexOf('.');
          String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
          if (proxyPkg == null) {
            proxyPkg = pkg;
          } else if (!pkg.equals(proxyPkg)) {
            throw new IllegalArgumentException(
              "non-public interfaces fromdifferent packages");
          }
        }
      }
 
      if (proxyPkg == null) {
        // 如果沒(méi)有非公開(kāi)的代理接口,使用com.sun.proxy作為包名
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
      }
 
      /* 生成代理類名的序號(hào)*/
      long num = nextUniqueNumber.getAndIncrement();
      //生成全類名
      String proxyName = proxyPkg + proxyClassNamePrefix + num;
 
      /*生成代理類字節(jié)碼 */
      byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName,interfaces);
      try {
        return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
      } catch (ClassFormatError e) {
        throw new IllegalArgumentException(e.toString());
      }
    }
}

在ProxyClassFactory中,可以看到產(chǎn)生代理類的具體邏輯,大致上是,根據(jù)傳遞的被代理類及其實(shí)現(xiàn)的接口生成代理類的字節(jié)碼加載到緩存中,但是加載到緩存中只是一個(gè).java文件也不能用,所以底層還有編譯等操作。到這里,可以大致的看清JDK中動(dòng)態(tài)代理的面孔了,實(shí)現(xiàn)的步驟為:

1.創(chuàng)建代理類的源碼;

2.對(duì)源碼進(jìn)行編譯成字節(jié)碼;

3.將字節(jié)碼加載到內(nèi)存;

4.實(shí)例化代理類對(duì)象并返回給調(diào)用者;

底層的代碼我們看不到,但是我們可以查看其生成的字節(jié)碼:

//獲得字節(jié)碼的測(cè)試方法
  byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy1", Car.class.getInterfaces()); 
    FileOutputStream out = null; 
    try { 
      out = new FileOutputStream(System.getProperty("user.dir") + "\\$Proxy1.class"); 
      out.write(classFile); 
      out.flush(); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } finally { 
      try { 
        out.close(); 
      } catch (IOException e) { 
        e.printStackTrace(); 
      } 
    }
 
//生成的字節(jié)碼:
importcn.com.goser.proxy.imooc.staticproxy.Moveable;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
 
public final class $Proxy1 extends Proxy
 implements Moveable
{
 private static Method m1;
 private static Method m3;
 private static Method m0;
 private static Method m2;
 
 public $Proxy1(InvocationHandler paramInvocationHandler)
  throws
 {
  super(paramInvocationHandler);
 }
 
 public final boolean equals(Object paramObject)
  throws
 {
  try
  {
   return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }
 
 public final void move()
  throws Exception
 {
  try
  {
   this.h.invoke(this, m3, null);
   return;
  }
  catch (Exception localException)
  {
   throw localException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }
 
 public final int hashCode()
  throws
 {
  try
  {
   return ((Integer)this.h.invoke(this, m0, null)).intValue();
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }
 
 public final String toString()
  throws
 {
  try
  {
   return (String)this.h.invoke(this, m2, null);
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }
 
 static
 {
  try
  {
   m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
   m3 = Class.forName("cn.com.goser.proxy.imooc.staticproxy.Moveable").getMethod("move", new Class[0]);
   m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
   m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
   return;
  }
  catch (NoSuchMethodExceptionlocalNoSuchMethodException)
  {
   throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  }
  catch (ClassNotFoundExceptionlocalClassNotFoundException)
  {
  }
  throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
 }
}

生成的字節(jié)碼比較長(zhǎng),但是在字節(jié)碼中最關(guān)鍵的信息是代理類的聲明:

public final class $Proxy1 extends Proxy

可以看到生成的代理類是繼承了Proxy類的,這就是說(shuō)明了為什么使用JDK動(dòng)態(tài)代理不能實(shí)現(xiàn)繼承式動(dòng)態(tài)代理,原因是Java不允許多繼承,而生成的代理類本身就已經(jīng)繼承了Proxy類。

至此,JDK的動(dòng)態(tài)代理的使用及底層原理分析完畢,揭下動(dòng)態(tài)代理的神秘面紗,果然是枚美女。

至于最底層的native方法是怎么動(dòng)態(tài)生成代理類的字節(jié)碼我們也可以簡(jiǎn)單的模擬一下,先分析下模擬的步驟:首先要生成一段代理類的源碼,然后將源碼編譯后生成代理類的實(shí)例返回給調(diào)用者。依據(jù)此步驟開(kāi)始編寫(xiě)我們的模擬代碼:

/**
 * JDK java.lang.reflect.Proxy的模擬
 * @author Goser  (mailto:goskalrie@163.com)
 * @Since 2016年9月7日
 */
public class Proxy {
  private static final String RT = "\r\n";
  public static Object newProxyInstance() throws Exception{
    //聲明一段源碼
    String sourceCode =
    "packagecn.com.goser.proxy.jdk.simulate;"+ RT +
    "importcn.com.goser.proxy.imooc.staticproxy.Admin;" + RT +
    "importcn.com.goser.proxy.imooc.staticproxy.Manager;" + RT +
    "http://以聚合方式實(shí)現(xiàn)的代理主題" + RT +
    "public class $Proxy0 implementsManager{" + RT +
    "  privateAdmin admin;" + RT +
    "  public$Proxy0(Admin admin) {" + RT +
    "    super();" + RT +
    "    this.admin= admin;" + RT +
    "  }" + RT +
    "  publicvoid doSomething() {" + RT +
    "    System.out.println(\"Log:admin操作開(kāi)始\");" + RT +
    "    admin.doSomething();" + RT +
    "    System.out.println(\"Log:admin操作結(jié)束\");" + RT +
    "  }" + RT +
    "}";
    String filename = System.getProperty("user.dir") + "/src/main/java/cn/com/goser/proxy/jdk/simulate/$Proxy0.java";
    File file = new File(filename);
    //使用org.apache.commons.io.FileUtils.writeStringToFile()將源碼寫(xiě)入磁盤(pán)
    //編寫(xiě)到處,可以運(yùn)行一下程序,可以在當(dāng)前目錄中看到生成的.java文件
    FileUtils.writeStringToFile(file,sourceCode);
    //獲得當(dāng)前系統(tǒng)中的編譯器
    JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
    //獲得文件管理者
    StandardJavaFileManager fileMgr =complier.getStandardFileManager(null, null, null);
    Iterable its =fileMgr.getJavaFileObjects(filename);
    //編譯任務(wù)
    CompilationTask task = complier.getTask(null, fileMgr, null, null, null, its);
    //開(kāi)始編譯,執(zhí)行完可在當(dāng)前目錄下看到.class文件
    task.call();
    fileMgr.close();
    //load到內(nèi)存
    ClassLoader loader = ClassLoader.getSystemClassLoader();
    Class cls = loader.loadClass("cn.com.goser.proxy.jdk.simulate.$Proxy0");
    //生成代理類對(duì)象
    Constructor ct = cls.getConstructor(Admin.class);
    return ct.newInstance(new Admin());
  }
}
class test{
  public static void main(String[] args) throws Exception {
    Manager m = (Manager)Proxy.newProxyInstance();
    m.doSomething();
  }
}

運(yùn)行測(cè)試代碼,結(jié)果和手工編寫(xiě)的結(jié)果一致,完成了JDK中動(dòng)態(tài)代理的實(shí)現(xiàn)模擬。

cglib動(dòng)態(tài)代理

前面分析到,因?yàn)镴ava只允許單繼承,而JDK生成的代理類本身就繼承了Proxy類,因此,使用JDK實(shí)現(xiàn)的動(dòng)態(tài)代理不能完成繼承式的動(dòng)態(tài)代理,但是我們可以使用cglib來(lái)實(shí)現(xiàn)繼承式的動(dòng)態(tài)代理。

大名鼎鼎的Spring中就含有cglib動(dòng)態(tài)代理,在此也以Spring中自帶的cglib完成動(dòng)態(tài)代理的實(shí)現(xiàn):

//1.具體主題
public class Train{
  public void move(){
    System.out.println("火車行駛中…");
  }
}
//2.生成代理
public class CGLibProxy implements MethodInterceptor {
  private Enhancer enhancer = new Enhancer();
  public Object getProxy(Class<!--?--> clazz){
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(this);
    return enhancer.create();
  }
  /**
   * 攔截所有目標(biāo)類方法的調(diào)用
   * 參數(shù):
   * obj目標(biāo)實(shí)例對(duì)象
   *method 目標(biāo)方法的反射對(duì)象
   * args方法的參數(shù)
   * proxy代理類的實(shí)例
   */
  public Object intercept(Object obj, Method method, Object[] args,
      MethodProxy proxy) throws Throwable {
    //代理類調(diào)用父類的方法
    System.out.println("日志開(kāi)始");
    proxy.invokeSuper(obj, args);
    System.out.println("日志結(jié)束");
    return null;
  }
}
//3.測(cè)試
public class Test {
  public static void main(String[] args) {
    CGLibProxy proxy = new CGLibProxy();
    Train t = (Train) proxy.getProxy(Train.class);
    t.move();
  }
}

小結(jié)

動(dòng)態(tài)代理與靜態(tài)代理相比較,最大的好處是接口中聲明的所有方法都被轉(zhuǎn)移到調(diào)用處理器一個(gè)集中的方法中處理。在接口方法數(shù)量比較多的時(shí)候,我們可以進(jìn)行靈活處理,而不需要像靜態(tài)代理那樣對(duì)每一個(gè)方法或方法組合進(jìn)行處理。Proxy 很美很強(qiáng)大,但是僅支持 interface 代理。Java 的單繼承機(jī)制注定了這些動(dòng)態(tài)代理類們無(wú)法實(shí)現(xiàn)對(duì) class 的動(dòng)態(tài)代理。好在有cglib為Proxy提供了彌補(bǔ)。class與interface的區(qū)別本來(lái)就模糊,在java8中更是增加了一些新特性,使得interface越來(lái)越接近c(diǎn)lass,當(dāng)有一日,java突破了單繼承的限制,動(dòng)態(tài)代理將會(huì)更加強(qiáng)大。

以上就是本文關(guān)于Java設(shè)計(jì)模式之代理模式原理及實(shí)現(xiàn)代碼分享的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:快速理解Java設(shè)計(jì)模式中的組合模式、Java設(shè)計(jì)者模式簡(jiǎn)單工廠模式解析、Java設(shè)計(jì)模式之訪問(wèn)者模式使用場(chǎng)景及代碼示例等,有什么問(wèn)題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家的。感謝朋友們對(duì)本站的支持!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI