真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

在Java中實現(xiàn)JDK動態(tài)代理的原理是什么

在Java中實現(xiàn)JDK動態(tài)代理的原理是什么?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計、成都做網(wǎng)站、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)泰來,十余年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18982081108

一、什么是代理?

代理是一種常用的設(shè)計模式,其目的就是為其他對象提供一個代理以控制對某個對象的訪問。代理類負(fù)責(zé)為委托類預(yù)處理消息,過濾消息并轉(zhuǎn)發(fā)消息,以及進行消息被委托類執(zhí)行后的后續(xù)處理。

代理模式UML圖:

在Java中實現(xiàn)JDK動態(tài)代理的原理是什么

簡單結(jié)構(gòu)示意圖:

在Java中實現(xiàn)JDK動態(tài)代理的原理是什么

為了保持行為的一致性,代理類和委托類通常會實現(xiàn)相同的接口,所以在訪問者看來兩者沒有絲毫的區(qū)別。通過代理類這中間一層,能有效控制對委托類對象的直接訪問,也可以很好地隱藏和保護委托類對象,同時也為實施不同控制策略預(yù)留了空間,從而在設(shè)計上獲得了更大的靈活性。Java 動態(tài)代理機制以巧妙的方式近乎完美地實踐了代理模式的設(shè)計理念。

二、Java 動態(tài)代理類

Java動態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個類:

(1)Interface InvocationHandler:該接口中僅定義了一個方法

publicobject invoke(Object obj,Method method, Object[] args)

在實際使用時,第一個參數(shù)obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數(shù)數(shù)組。這個抽象方法在代理類中動態(tài)實現(xiàn)。

(2)Proxy:該類即為動態(tài)代理類,其中主要包含以下內(nèi)容:

protected Proxy(InvocationHandler h) :構(gòu)造函數(shù),用于給內(nèi)部的h賦值。

static Class getProxyClass (ClassLoaderloader, Class[] interfaces) :獲得一個代理類,其中l(wèi)oader是類裝載器,interfaces是真實類所擁有的全部接口的數(shù)組。

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) :返回代理類的一個實例,返回后的代理類可以當(dāng)作被代理類使用(可使用被代理類的在Subject接口中聲明過的方法)

所謂DynamicProxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,然后該class就宣稱它實現(xiàn)了這些 interface。你當(dāng)然可以把該class的實例當(dāng)作這些interface中的任何一個來用。當(dāng)然,這個DynamicProxy其實就是一個Proxy,它不會替你作實質(zhì)性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作。

在使用動態(tài)代理類時,我們必須實現(xiàn)InvocationHandler接口

通過這種方式,被代理的對象(RealSubject)可以在運行時動態(tài)改變,需要控制的接口(Subject接口)可以在運行時改變,控制的方式(DynamicSubject類)也可以動態(tài)改變,從而實現(xiàn)了非常靈活的動態(tài)代理關(guān)系。

動態(tài)代理步驟:

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

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

       3.通過Proxy的靜態(tài)方法

           newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)創(chuàng)建一個代理

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

三、JDK的動態(tài)代理怎么使用?

1、需要動態(tài)代理的接口:

package jiankunking; 
 
/** 
 * 需要動態(tài)代理的接口 
 */ 
public interface Subject 
{ 
 /** 
 * 你好 
 * 
 * @param name 
 * @return 
 */ 
 public String SayHello(String name); 
 
 /** 
 * 再見 
 * 
 * @return 
 */ 
 public String SayGoodBye(); 
}

2、需要代理的實際對象

package jiankunking; 
 
/** 
 * 實際對象 
 */ 
public class RealSubject implements Subject 
{ 
 
 /** 
 * 你好 
 * 
 * @param name 
 * @return 
 */ 
 public String SayHello(String name) 
 { 
 return "hello " + name; 
 } 
 
 /** 
 * 再見 
 * 
 * @return 
 */ 
 public String SayGoodBye() 
 { 
 return " good bye "; 
 } 
}

3、調(diào)用處理器實現(xiàn)類(有木有感覺這里就是傳說中的AOP啊)

package jiankunking; 
 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
 
 
/** 
 * 調(diào)用處理器實現(xiàn)類 
 * 每次生成動態(tài)代理類對象時都需要指定一個實現(xiàn)了該接口的調(diào)用處理器對象 
 */ 
public class InvocationHandlerImpl implements InvocationHandler 
{ 
 
 /** 
 * 這個就是我們要代理的真實對象 
 */ 
 private Object subject; 
 
 /** 
 * 構(gòu)造方法,給我們要代理的真實對象賦初值 
 * 
 * @param subject 
 */ 
 public InvocationHandlerImpl(Object subject) 
 { 
 this.subject = subject; 
 } 
 
 /** 
 * 該方法負(fù)責(zé)集中處理動態(tài)代理類上的所有方法調(diào)用。 
 * 調(diào)用處理器根據(jù)這三個參數(shù)進行預(yù)處理或分派到委托類實例上反射執(zhí)行 
 * 
 * @param proxy 代理類實例 
 * @param method 被調(diào)用的方法對象 
 * @param args 調(diào)用參數(shù) 
 * @return 
 * @throws Throwable 
 */ 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
 { 
 //在代理真實對象前我們可以添加一些自己的操作 
 System.out.println("在調(diào)用之前,我要干點啥呢?"); 
 
 System.out.println("Method:" + method); 
 
 //當(dāng)代理對象調(diào)用真實對象的方法時,其會自動的跳轉(zhuǎn)到代理對象關(guān)聯(lián)的handler對象的invoke方法來進行調(diào)用 
 Object returnValue = method.invoke(subject, args); 
 
 //在代理真實對象后我們也可以添加一些自己的操作 
 System.out.println("在調(diào)用之后,我要干點啥呢?"); 
 
 return returnValue; 
 } 
}

4、測試

package jiankunking; 
 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Proxy; 
 
/** 
 * 動態(tài)代理演示 
 */ 
public class DynamicProxyDemonstration 
{ 
 public static void main(String[] args) 
 { 
 //代理的真實對象 
 Subject realSubject = new RealSubject(); 
 
 /** 
 * InvocationHandlerImpl 實現(xiàn)了 InvocationHandler 接口,并能實現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā) 
 * 其內(nèi)部通常包含指向委托類實例的引用,用于真正執(zhí)行分派轉(zhuǎn)發(fā)過來的方法調(diào)用. 
 * 即:要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調(diào)用其方法 
 */ 
 InvocationHandler handler = new InvocationHandlerImpl(realSubject); 
 
 ClassLoader loader = realSubject.getClass().getClassLoader(); 
 Class[] interfaces = realSubject.getClass().getInterfaces(); 
 /** 
 * 該方法用于為指定類裝載器、一組接口及調(diào)用處理器生成動態(tài)代理類實例 
 */ 
 Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler); 
 
 System.out.println("動態(tài)代理對象的類型:"+subject.getClass().getName()); 
 
 String hello = subject.SayHello("jiankunking"); 
 System.out.println(hello); 
// String goodbye = subject.SayGoodBye(); 
// System.out.println(goodbye); 
 } 
 
}

5、輸出結(jié)果如下:

演示demo下載地址:http://xiazai.jb51.net/201707/yuanma/DynamicProxyDemo(jb51.net).rar

四、動態(tài)代理怎么實現(xiàn)的?

從使用代碼中可以看出,關(guān)鍵點在:

Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

通過跟蹤提示代碼可以看出:當(dāng)代理對象調(diào)用真實對象的方法時,其會自動的跳轉(zhuǎn)到代理對象關(guān)聯(lián)的handler對象的invoke方法來進行調(diào)用。

也就是說,當(dāng)代碼執(zhí)行到:

subject.SayHello("jiankunking")這句話時,會自動調(diào)用InvocationHandlerImpl的invoke方法。這是為啥呢?

=======橫線之間的是代碼跟分析的過程,不想看的朋友可以直接看結(jié)論============

以下代碼來自:JDK1.8.0_92

既然生成代理對象是用的Proxy類的靜態(tài)方newProxyInstance,那么我們就去它的源碼里看一下它到底都做了些什么?

/** 
 * Returns an instance of a proxy class for the specified interfaces 
 * that dispatches method invocations to the specified invocation 
 * handler. 
 * 
 * 

{@code Proxy.newProxyInstance} throws   * {@code IllegalArgumentException} for the same reasons that   * {@code Proxy.getProxyClass} does.   *   * @param loader the class loader to define the proxy class   * @param interfaces the list of interfaces for the proxy class   * to implement   * @param h the invocation handler to dispatch method invocations to   * @return a proxy instance with the specified invocation handler of a   * proxy class that is defined by the specified class loader   * and that implements the specified interfaces   * @throws IllegalArgumentException if any of the restrictions on the   * parameters that may be passed to {@code getProxyClass}   * are violated   * @throws SecurityException if a security manager, s, is present   * and any of the following conditions is met:   * 

       * 
  •  the given {@code loader} is {@code null} and   * the caller's class loader is not {@code null} and the   * invocation of {@link SecurityManager#checkPermission   * s.checkPermission} with   * {@code RuntimePermission("getClassLoader")} permission   * denies access;
  •    * 
  •  for each proxy interface, {@code intf},   * the caller's class loader is not the same as or an   * ancestor of the class loader for {@code intf} and   * invocation of {@link SecurityManager#checkPackageAccess   * s.checkPackageAccess()} denies access to {@code intf};
  •    * 
  •  any of the given proxy interfaces is non-public and the   * caller class is not in the same {@linkplain Package runtime package}   * as the non-public interface and the invocation of   * {@link SecurityManager#checkPermission s.checkPermission} with   * {@code ReflectPermission("newProxyInPackage.{package name}")}   * permission denies access.
  •    * 
   * @throws NullPointerException if the {@code interfaces} array   * argument or any of its elements are {@code null}, or   * if the invocation handler, {@code h}, is   * {@code null}   */  @CallerSensitive  public static Object newProxyInstance(ClassLoader loader,     Class[] interfaces,     InvocationHandler h)   throws IllegalArgumentException   {   //檢查h 不為空,否則拋異常   Objects.requireNonNull(h);     final Class[] intfs = interfaces.clone();   final SecurityManager sm = System.getSecurityManager();   if (sm != null) {   checkProxyAccess(Reflection.getCallerClass(), loader, intfs);   }     /*   * 獲得與指定類裝載器和一組接口相關(guān)的代理類類型對象   */   Class cl = getProxyClass0(loader, intfs);     /*   * 通過反射獲取構(gòu)造函數(shù)對象并生成代理類實例   */   try {   if (sm != null) {   checkNewProxyPermission(Reflection.getCallerClass(), cl);   }   //獲取代理對象的構(gòu)造方法(也就是$Proxy0(InvocationHandler h))   final Constructor cons = cl.getConstructor(constructorParams);   final InvocationHandler ih = h;   if (!Modifier.isPublic(cl.getModifiers())) {   AccessController.doPrivileged(new PrivilegedAction() {    public Void run() {    cons.setAccessible(true);    return null;    }   });   }   //生成代理類的實例并把InvocationHandlerImpl的實例傳給它的構(gòu)造方法   return cons.newInstance(new Object[]{h});   } catch (IllegalAccessException|InstantiationException e) {   throw new InternalError(e.toString(), e);   } catch (InvocationTargetException e) {   Throwable t = e.getCause();   if (t instanceof RuntimeException) {   throw (RuntimeException) t;   } else {   throw new InternalError(t.toString(), t);   }   } catch (NoSuchMethodException e) {   throw new InternalError(e.toString(), e);   }   }

我們再進去getProxyClass0方法看一下:

/** 
 * Generate a proxy class. Must call the checkProxyAccess method 
 * to perform permission checks before calling this. 
 */ 
 private static Class getProxyClass0(ClassLoader loader, 
   Class... interfaces) { 
 if (interfaces.length > 65535) { 
 throw new IllegalArgumentException("interface limit exceeded"); 
 } 
 
 // If the proxy class defined by the given loader implementing 
 // the given interfaces exists, this will simply return the cached copy; 
 // otherwise, it will create the proxy class via the ProxyClassFactory 
 return proxyClassCache.get(loader, interfaces); 
 }

 真相還是沒有來到,繼續(xù),看一下proxyClassCache

/** 
 * a cache of proxy classes 
 */ 
 private static final WeakCache[], Class> 
 proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

奧,原來用了一下緩存啊

那么它對應(yīng)的get方法啥樣呢?

/** 
 * Look-up the value through the cache. This always evaluates the 
 * {@code subKeyFactory} function and optionally evaluates 
 * {@code valueFactory} function if there is no entry in the cache for given 
 * pair of (key, subKey) or the entry has already been cleared. 
 * 
 * @param key possibly null key 
 * @param parameter parameter used together with key to create sub-key and 
 *  value (should not be null) 
 * @return the cached value (never null) 
 * @throws NullPointerException if {@code parameter} passed in or 
 *  {@code sub-key} calculated by 
 *  {@code subKeyFactory} or {@code value} 
 *  calculated by {@code valueFactory} is null. 
 */ 
 public V get(K key, P parameter) { 
 Objects.requireNonNull(parameter); 
 
 expungeStaleEntries(); 
 
 Object cacheKey = CacheKey.valueOf(key, refQueue); 
 
 // lazily install the 2nd level valuesMap for the particular cacheKey 
 ConcurrentMap> valuesMap = map.get(cacheKey); 
 if (valuesMap == null) { 
 //putIfAbsent這個方法在key不存在的時候加入一個值,如果key存在就不放入 
 ConcurrentMap> oldValuesMap 
 = map.putIfAbsent(cacheKey, 
   valuesMap = new ConcurrentHashMap<>()); 
 if (oldValuesMap != null) { 
 valuesMap = oldValuesMap; 
 } 
 } 
 
 // create subKey and retrieve the possible Supplier stored by that 
 // subKey from valuesMap 
 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); 
 Supplier supplier = valuesMap.get(subKey); 
 Factory factory = null; 
 
 while (true) { 
 if (supplier != null) { 
 // supplier might be a Factory or a CacheValue instance 
 V value = supplier.get(); 
 if (value != null) { 
  return value; 
 } 
 } 
 // else no supplier in cache 
 // or a supplier that returned null (could be a cleared CacheValue 
 // or a Factory that wasn't successful in installing the CacheValue) 
 
 // lazily construct a Factory 
 if (factory == null) { 
 factory = new Factory(key, parameter, subKey, valuesMap); 
 } 
 
 if (supplier == null) { 
 supplier = valuesMap.putIfAbsent(subKey, factory); 
 if (supplier == null) { 
  // successfully installed Factory 
  supplier = factory; 
 } 
 // else retry with winning supplier 
 } else { 
 if (valuesMap.replace(subKey, supplier, factory)) { 
  // successfully replaced 
  // cleared CacheEntry / unsuccessful Factory 
  // with our Factory 
  supplier = factory; 
 } else { 
  // retry with current supplier 
  supplier = valuesMap.get(subKey); 
 } 
 } 
 } 
 }

我們可以看到它調(diào)用了 supplier.get(); 獲取動態(tài)代理類,其中supplier是Factory,這個類定義在WeakCach的內(nèi)部。

來瞅瞅,get里面又做了什么?

public synchronized V get() { // serialize access 
 // re-check 
 Supplier supplier = valuesMap.get(subKey); 
 if (supplier != this) { 
 // something changed while we were waiting: 
 // might be that we were replaced by a CacheValue 
 // or were removed because of failure -> 
 // return null to signal WeakCache.get() to retry 
 // the loop 
 return null; 
 } 
 // else still us (supplier == this) 
 
 // create new value 
 V value = null; 
 try { 
 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); 
 } finally { 
 if (value == null) { // remove us on failure 
  valuesMap.remove(subKey, this); 
 } 
 } 
 // the only path to reach here is with non-null value 
 assert value != null; 
 
 // wrap value with CacheValue (WeakReference) 
 CacheValue cacheValue = new CacheValue<>(value); 
 
 // try replacing us with CacheValue (this should always succeed) 
 if (valuesMap.replace(subKey, this, cacheValue)) { 
 // put also in reverseMap 
 reverseMap.put(cacheValue, Boolean.TRUE); 
 } else { 
 throw new AssertionError("Should not reach here"); 
 } 
 
 // successfully replaced us with new CacheValue -> return the value 
 // wrapped by it 
 return value; 
 } 
 }

發(fā)現(xiàn)重點還是木有出現(xiàn),但我們可以看到它調(diào)用了valueFactory.apply(key, parameter)方法:

/** 
 * A factory function that generates, defines and returns the proxy class given 
 * the ClassLoader and array of interfaces. 
 */ 
 private static final class ProxyClassFactory 
 implements BiFunction[], Class> 
 { 
 // prefix for all proxy class names 
 private static final String proxyClassNamePrefix = "$Proxy"; 
 
 // next number to use for generation of unique proxy class names 
 private static final AtomicLong nextUniqueNumber = new AtomicLong(); 
 
 @Override 
 public Class apply(ClassLoader loader, Class[] interfaces) { 
 
 Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); 
 for (Class intf : interfaces) { 
 /* 
 * Verify that the class loader resolves the name of this 
 * interface to the same Class object. 
 */ 
 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 class loader"); 
 } 
 /* 
 * Verify that the Class object actually represents an 
 * interface. 
 */ 
 if (!interfaceClass.isInterface()) { 
  throw new IllegalArgumentException( 
  interfaceClass.getName() + " is not an interface"); 
 } 
 /* 
 * Verify that this interface is not a duplicate. 
 */ 
 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { 
  throw new IllegalArgumentException( 
  "repeated interface: " + interfaceClass.getName()); 
 } 
 } 
 
 String proxyPkg = null; // package to define proxy class in 
 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; 
 
 /* 
 * Record the package of a non-public proxy interface so that the 
 * proxy class will be defined in the same package. Verify that 
 * all non-public proxy interfaces are in the same package. 
 */ 
 for (Class intf : interfaces) { 
 int flags = intf.getModifiers(); 
 if (!Modifier.isPublic(flags)) { 
  accessFlags = Modifier.FINAL; 
  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 from different packages"); 
  } 
 } 
 } 
 
 if (proxyPkg == null) { 
 // if no non-public proxy interfaces, use com.sun.proxy package 
 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; 
 } 
 
 /* 
 * Choose a name for the proxy class to generate. 
 */ 
 long num = nextUniqueNumber.getAndIncrement(); 
 String proxyName = proxyPkg + proxyClassNamePrefix + num; 
 
 /* 
 * Generate the specified proxy class. 
 */ 
 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( 
 proxyName, interfaces, accessFlags); 
 try { 
 return defineClass0(loader, proxyName, 
   proxyClassFile, 0, proxyClassFile.length); 
 } catch (ClassFormatError e) { 
 /* 
 * A ClassFormatError here means that (barring bugs in the 
 * proxy class generation code) there was some other 
 * invalid aspect of the arguments supplied to the proxy 
 * class creation (such as virtual machine limitations 
 * exceeded). 
 */ 
 throw new IllegalArgumentException(e.toString()); 
 } 
 } 
 }

通過看代碼終于找到了重點:

//生成字節(jié)碼 
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

那么接下來我們也使用測試一下,使用這個方法生成的字節(jié)碼是個什么樣子:

package jiankunking; 
 
import sun.misc.ProxyGenerator; 
 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Proxy; 
 
/** 
 * 動態(tài)代理演示 
 */ 
public class DynamicProxyDemonstration 
{ 
 public static void main(String[] args) 
 { 
 //代理的真實對象 
 Subject realSubject = new RealSubject(); 
 
 /** 
 * InvocationHandlerImpl 實現(xiàn)了 InvocationHandler 接口,并能實現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā) 
 * 其內(nèi)部通常包含指向委托類實例的引用,用于真正執(zhí)行分派轉(zhuǎn)發(fā)過來的方法調(diào)用. 
 * 即:要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調(diào)用其方法 
 */ 
 InvocationHandler handler = new InvocationHandlerImpl(realSubject); 
 
 ClassLoader loader = handler.getClass().getClassLoader(); 
 Class[] interfaces = realSubject.getClass().getInterfaces(); 
 /** 
 * 該方法用于為指定類裝載器、一組接口及調(diào)用處理器生成動態(tài)代理類實例 
 */ 
 Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler); 
 
 System.out.println("動態(tài)代理對象的類型:"+subject.getClass().getName()); 
 
 String hello = subject.SayHello("jiankunking"); 
 System.out.println(hello); 
 // 將生成的字節(jié)碼保存到本地, 
 createProxyClassFile(); 
 } 
 private static void createProxyClassFile(){ 
 String name = "ProxySubject"; 
 byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class}); 
 FileOutputStream out =null; 
 try { 
 out = new FileOutputStream(name+".class"); 
 System.out.println((new File("hello")).getAbsolutePath()); 
 out.write(data); 
 } catch (FileNotFoundException e) { 
 e.printStackTrace(); 
 } catch (IOException e) { 
 e.printStackTrace(); 
 }finally { 
 if(null!=out) try { 
 out.close(); 
 } catch (IOException e) { 
 e.printStackTrace(); 
 } 
 } 
 } 
 
}

可以看一下這里代理對象的類型:

在Java中實現(xiàn)JDK動態(tài)代理的原理是什么

我們用jd-jui 工具將生成的字節(jié)碼反編譯:

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
import java.lang.reflect.UndeclaredThrowableException; 
import jiankunking.Subject; 
 
public final class ProxySubject 
 extends Proxy 
 implements Subject 
{ 
 private static Method m1; 
 private static Method m3; 
 private static Method m4; 
 private static Method m2; 
 private static Method m0; 
 
 public ProxySubject(InvocationHandler paramInvocationHandler) 
 { 
 super(paramInvocationHandler); 
 } 
 
 public final boolean equals(Object paramObject) 
 { 
 try 
 { 
 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); 
 } 
 catch (Error|RuntimeException localError) 
 { 
 throw localError; 
 } 
 catch (Throwable localThrowable) 
 { 
 throw new UndeclaredThrowableException(localThrowable); 
 } 
 } 
 
 public final String SayGoodBye() 
 { 
 try 
 { 
 return (String)this.h.invoke(this, m3, null); 
 } 
 catch (Error|RuntimeException localError) 
 { 
 throw localError; 
 } 
 catch (Throwable localThrowable) 
 { 
 throw new UndeclaredThrowableException(localThrowable); 
 } 
 } 
 
 public final String SayHello(String paramString) 
 { 
 try 
 { 
 return (String)this.h.invoke(this, m4, new Object[] { paramString }); 
 } 
 catch (Error|RuntimeException localError) 
 { 
 throw localError; 
 } 
 catch (Throwable localThrowable) 
 { 
 throw new UndeclaredThrowableException(localThrowable); 
 } 
 } 
 
 public final String toString() 
 { 
 try 
 { 
 return (String)this.h.invoke(this, m2, null); 
 } 
 catch (Error|RuntimeException localError) 
 { 
 throw localError; 
 } 
 catch (Throwable localThrowable) 
 { 
 throw new UndeclaredThrowableException(localThrowable); 
 } 
 } 
 
 public final int hashCode() 
 { 
 try 
 { 
 return ((Integer)this.h.invoke(this, m0, null)).intValue(); 
 } 
 catch (Error|RuntimeException localError) 
 { 
 throw localError; 
 } 
 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("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]); 
 m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") }); 
 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); 
 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); 
 return; 
 } 
 catch (NoSuchMethodException localNoSuchMethodException) 
 { 
 throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); 
 } 
 catch (ClassNotFoundException localClassNotFoundException) 
 { 
 throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); 
 } 
 } 
}

這就是最終真正的代理類,它繼承自Proxy并實現(xiàn)了我們定義的Subject接口

也就是說:

Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

這里的subject實際是這個類的一個實例,那么我們調(diào)用它的:

public final String SayHello(String paramString)

就是調(diào)用我們定義的InvocationHandlerImpl的 invoke方法:

在Java中實現(xiàn)JDK動態(tài)代理的原理是什么

=======橫線之間的是代碼跟分析的過程,不想看的朋友可以直接看結(jié)論================

五、結(jié)論

到了這里,終于解答了:

subject.SayHello("jiankunking")這句話時,為什么會自動調(diào)用InvocationHandlerImpl的invoke方法?

因為JDK生成的最終真正的代理類,它繼承自Proxy并實現(xiàn)了我們定義的Subject接口,在實現(xiàn)Subject接口方法的內(nèi)部,通過反射調(diào)用了InvocationHandlerImpl的invoke方法。

包含生成本地class文件的demo:

http://xiazai.jb51.net/201707/yuanma/DynamicProxyDemo2(jb51.net).rar

通過分析代碼可以看出Java 動態(tài)代理,具體有如下四步驟:

  • 通過實現(xiàn) InvocationHandler 接口創(chuàng)建自己的調(diào)用處理器;

  • 通過為 Proxy 類指定 ClassLoader 對象和一組 interface 來創(chuàng)建動態(tài)代理類;

  • 通過反射機制獲得動態(tài)代理類的構(gòu)造函數(shù),其唯一參數(shù)類型是調(diào)用處理器接口類型;

  • 通過構(gòu)造函數(shù)創(chuàng)建動態(tài)代理類實例,構(gòu)造時調(diào)用處理器對象作為參數(shù)被傳入。

看完上述內(nèi)容,你們掌握在Java中實現(xiàn)JDK動態(tài)代理的原理是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


當(dāng)前文章:在Java中實現(xiàn)JDK動態(tài)代理的原理是什么
本文URL:http://weahome.cn/article/pcejsd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部