吃透动态代理,解密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就有了前置加强和后置加强。到这里已经解开了动态代理的原理

相关文章
相关标签/搜索