国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

jdk動態代理源碼學習

2019-11-14 22:00:22
字體:
來源:轉載
供稿:網友
jdk動態代理源碼學習

最近用到了java的動態代理,雖然會用,但不了解他具體是怎么實現,抽空看看了看他的源碼。

說到Java的動態代理就不能不說到代理模式,動態代理也就是多了一個’動態’兩字,在《大話設計模式》中不是有這句話嗎?“反射,反射程序員的快樂”,這里也不例外,他在底層也是使用了反射來創建對象。

一、 為了讓我們更加明白的了解動態代理,我們先來復習一下代理模式吧(沒有學過的,也得假裝復習是復習呀,不然掉面)。

public interface BookManager {  void addBook();}

  

 1 package com.test; 2  3 public class Library implements BookManager { 4  5     public void addBook() { 6         // TODO Auto-generated method stub 7         System.out.

 1 package com.test; 2  3 public class Agent implements BookManager { 4     private BookManager library; 5      6     public BookManager getLibrary() { 7         return library; 8     } 9 10     public void setLibrary(BookManager library) {11         this.library = library;12     }13 14     public void addBook() {15         // TODO Auto-generated method stub16         System.out.println("添加圖書之前");17         library.addBook();18         System.out.println("添加圖書之后");19     }20 21 }

測試代碼

package com.test;public class BookTest {public static void main(String[] args) {BookManager library = new Library();Agent agent =  new Agent();agent.setLibrary(library);agent.addBook();}}執行結果為添加圖書之前增加圖書。。。。。添加圖書之后

從這里可以看到在代理模式中要求是都實現了相同的接口,所以這樣的代碼,移植性不強,所以催生出動態代理。動態代理不要求,必須實現相同的接口,減少了代碼量。

先上代碼

public interface BookFacade {public void addBook(); }

  

public class BookFacadeImpl implements BookFacade,system {public void addBook() {// TODO Auto-generated method stubSystem.out.println("增加圖書方法。。。");  }public void doSys() {// TODO Auto-generated method stubSystem.out.println("dsfsdfsd");}}

  

public class BookFacadeProxy implements InvocationHandler {private Object target;      /**      * 綁定委托對象并返回一個代理類      * @param target      * @return      */      public Object bind(Object target) {          this.target = target;          //取得代理對象          return Proxy.newProxyInstance(target.getClass().getClassLoader(),                  target.getClass().getInterfaces(), this);   //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)      }        public Object invoke(Object proxy, Method method, Object[] args)              throws Throwable {          Object result=null;          System.out.println("事物開始");          //執行方法          System.out.println("ClassLoad"+proxy.getClass().getSimpleName());        result=method.invoke(target, args);          System.out.println("事物結束");          return result;      }  }

  

public class TestProxy {public static void main(String[] args) { BookFacadeProxy proxy = new BookFacadeProxy();          BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());          bookProxy.addBook();         ProxyGeneratorUtils.writeProxyClassToHardDisk("F:/$Proxy11.class");}}

  我先聲明后面這段代碼我盜用了其他網友的成果。

先說明用法,再來解釋為什么會是這樣的呢?

第一步 你必須得聲明一個接口,而且在目標類必須實現這個接口,不然你使用動態代理是不會成功的。

第二步 需要實現 InvocationHandler 接口,創建一個代理類,這個代理類里需要重寫invoke方法,在這個方法里,需要寫上多被代理對象的調用method.invoke(target, args),如果不知道method.invoke()是做什么用的,可以去看看反射就明白了。參數有兩個一個是被代理的對象,第二個就是調用該方法的參數

第三步 需要獲得代理對象,可以通過Object Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

方法來生成一個代理對象。

具體的第一個是使用那一個類加載器加載,第二個就是需要綁定的接口,第三個就是持有處理的對象。

測試方法安裝你正常調用相應的方法就行。

測試類執行結果如下

事物開始增加圖書方法。。。事物結束

現在我們知道用法了,按照我們一般考慮問題的思路是,

生成的代理對象,能調用接口的的方法,肯定是實現了接口這是我們的猜想一,這個涉及到代理對象的生成。

第二個調用addBook方法,能執行,invoke方法,他是怎么調用的呢。

那么我們現在就進入源碼吧,先來看看對象是怎么生成的。

Returns an instance of a proxy class for the specified interfaces  that dispatches method invocations to the specified invocation handler.看看注釋就明白了,返回一個代理類的對象,而且還是實現了你進來接口的類public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)        throws IllegalArgumentException    {        if (h == null) {            throw new NullPointerException();        }        /*         * 生成一個代理類         */        Class<?> cl = getProxyClass(loader, interfaces);        /*         * 通過反射用構造方法生成一個對象         */        try {            Constructor cons = cl.getConstructor(constructorParams);            return cons.newInstance(new Object[] { h });        } catch (NoSuchMethodException e) {            throw new InternalError(e.toString());        } catch (IllegalaccessException e) {            throw new InternalError(e.toString());        } catch (InstantiationException e) {            throw new InternalError(e.toString());        } catch (InvocationTargetException e) {            throw new InternalError(e.toString());        }    }

  上面大家可以看到,生成了一個對象返回去了,這個對象就是我們所說的代理對象,那么我們可以看看這個class 是怎么生成?

public static Class<?> getProxyClass(ClassLoader loader,                                         Class<?>... interfaces)        throws IllegalArgumentException    {        驗證接口的長度        if (interfaces.length > 65535) {            throw new IllegalArgumentException("interface limit exceeded");        }        這個class 對象就是我們被返回對象的定義        Class<?> proxyClass = null;        /* collect interface names to use as key for proxy class cache */        String[] interfaceNames = new String[interfaces.length];        // for detecting duplicates        Set<Class<?>> interfaceSet = new HashSet<>();                    for (int i = 0; i < interfaces.length; i++) {                       String interfaceName = interfaces[i].getName();            Class<?> interfaceClass = null;            try {                interfaceClass = Class.forName(interfaceName, false, loader);            } catch (ClassNotFoundException e) {            }            if (interfaceClass != interfaces[i]) {                throw new IllegalArgumentException(                    interfaces[i] + " 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.contains(interfaceClass)) {                throw new IllegalArgumentException(                    "repeated interface: " + interfaceClass.getName());            }            interfaceSet.add(interfaceClass);            interfaceNames[i] = interfaceName;        }        ....... 中間省略N多                                           生成一個代理class文件,這個就是我們要被返回的class 對象                /*                 * Generate the specified proxy class.                 */                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(                    proxyName, interfaces);                try {                    proxyClass = defineClass0(loader, proxyName,                        proxyClassFile, 0, proxyClassFile.length);                } catch (ClassFormatError e) {                    /*                

  這樣我們就知道這個代理對象是怎么生成的。

接下來我們第2個問題就是這個invoke 方法是什么時候調用的。

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(                    proxyName, interfaces); 

  從這個方法我們可以看出來,他可以生成一個二進制的文件,那么我們把這個文件寫到本地就可以看到這個文件了。

public final class $Proxy110 extends Proxy  implements BookFacade{  private static Method m1;  private static Method m3;  private static Method m0;  private static Method m2;  public $Proxy110(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 (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final void addBook()    throws   {    try    {      this.h.invoke(this, m3, null);      return;    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }

  這個是生成


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌鲁木齐县| 攀枝花市| 绥化市| 泗水县| 保靖县| 祁门县| 台中市| 岐山县| 阳信县| 永和县| 牙克石市| 高尔夫| 铁力市| 西盟| 时尚| 临桂县| 巨野县| 五常市| 甘洛县| 河源市| 威信县| 黄浦区| 松桃| 仙桃市| 鄂温| 方正县| 新宁县| 泸水县| 岳阳市| 石台县| 苏尼特左旗| 东阿县| 浦东新区| 香河县| 山东省| 榆社县| 长海县| 南川市| 甘洛县| 浏阳市| 周口市|