吃透動態代理,解密spring AOP源碼(三)

  • 上節講到動態代理生成的類爲$Proxy0,可是在咱們項目裏面卻不存在,實際咱們是用了這個實現類調用了方法,想要知道這個問題,首先要理解類的完整生命週期.

類的完整生命週期

clipboard.png

Java源文件:即咱們在IDE裏面寫的.java文件java

Java字節碼:即編譯器編譯以後的.class文件(javac命令).備註:Java代碼爲什麼可以跨平臺,和Java字節碼技術是分不開的,這個字節碼在windows,在linux下都是能夠運行的linux

class對象:工程啓動的時候classLoader類加載器會掃描這些字節碼並加載到classLoader上面生成class對象,有了類對象,即可以new實例了。(class對象保存在方法區元空間JDK1.8)算法

卸載:垃圾回收,關於回收機制,算法有興趣能夠去了解。class對象何時被回收?答:可達性分析,當發現某個類不被引用,類會被回收windows

類的生命週期與動態代理關係

  • 動態代理是沒有Java源文件,直接生成Java字節碼的,加載到JVM上面的。字節碼來源於內存,好比tomcat的熱加載就是從網絡傳輸過來的。

既然是直接生成的Java字節碼,是怎麼生成的?從源碼開始分析,從Proxy.newProxyInstance方法開始看。數組

clipboard.png

Class<?> cl = getProxyClass0(loader, intfs);這行代碼生成了.class字節碼而且生成了class對象,而後拿這個類對象獲取構造函數,再newInstance,生成實例對象,是經過反射的機制。重點仍是怎麼生成.class字節碼。tomcat

clipboard.png

clipboard.png
接下來apply()方法往下看網絡

clipboard.png

生成了字節碼數組,從而生成了Java字節碼,defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length)則是加載字節碼文件,此方法爲native方法,C語言方法,操做系統類庫(C/C++/彙編)。app

字節碼文件的結構是如何的呢?咱們把class文件生成出來並在反編譯工具打開,這裏就用到了源碼裏面的方法了。生成.class文件的代碼以下:函數

public static void generateClass(String proxyName, Class[] paramArrayOfClass, Class clazz) throws IOException {
        byte[]  classFile=ProxyGenerator.generateProxyClass(
                proxyName, paramArrayOfClass);
        String path=clazz.getResource(".").getPath();
        System.out.println(path);
        FileOutputStream outputStream =null;
        outputStream = new FileOutputStream(path + proxyName + "p.class");
        outputStream.write(classFile);
        outputStream.flush();
        outputStream.close();
    }

在剛剛的動態代理測試類增長几行代碼:工具

public static void main(String[] args) throws IOException {
        // 代購公司C,負責代購全部產品
        DynamicProxyCompanyC proxy = new DynamicProxyCompanyC();
        // 日本有家A公司生產男性用品
        ManToolFactory dogToolFactory = new AManFactory();
        // 代購A公司的產品
        proxy.setFactory(dogToolFactory);
        // 建立A公司的代理對象
        ManToolFactory proxyObject = (ManToolFactory) proxy.getProxyInstance();
        // 代理對象完成代購男性用品
        proxyObject.saleManTool("D");
        System.out.println("--------------");
        // 日本有家B公司生產女性用品
        WomanToolFactory womanToolFactory = new BWomanFactory();
        // 代購B公司的產品
        proxy.setFactory(womanToolFactory);
        // 建立B公司的代理對象
        WomanToolFactory proxyObject1 = (WomanToolFactory) proxy.getProxyInstance();
        // 代理對象完成代購女性用品
        proxyObject1.saleWomanTool(1.8);
        //生成代理類的.class文件
        DynamicProxyCompanyC.generateClass(proxyObject1.getClass().getSimpleName(),
                womanToolFactory.getClass().getInterfaces(), womanToolFactory.getClass());
    }

根據打印出來的class文件路徑打開並在反編譯工具上打開

clipboard.png

動態代理生成的類就是這個了,調用業務方法saleWomanTool實際上變成了這個h.invoke,而這個h是全部Proxy類裏面含有的 protected InvocationHandler h;(源碼可見),在用Proxy建立代理實例的時候已經傳入過了。

clipboard.png

因此調用方法saleWomanTool就有了前置加強和後置加強。到這裏已經解開了動態代理的原理

相關文章
相關標籤/搜索