欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SPRING-AOP之动态代理,核心原理深入理解

程序员文章站 2022-07-10 18:49:22
最近在学Sping-aop,顺便把动态代理深入研究一下。实现方法有2种第一种:1、自定义接口2、自定义接口实现类3、自定义实现InvocationHandler接口的代理类第二种:1、自定义接口2、自定义接口实现类3、直接搞起来第一种实现完觉得麻烦,直接上第二种实现代码public static void main(String[] args) throws IOException { JiehunImpl proxy = new JiehunI...

最近在学Sping-aop,顺便把动态代理深入研究一下。

实现方法有2种

第一种:

1、自定义接口

2、自定义接口实现类

3、自定义实现InvocationHandler接口的代理类

第二种:

1、自定义接口

2、自定义接口实现类

3、直接搞起来

第一种实现完觉得麻烦,直接上第二种实现代码(~~虽然第一种更符合Spring的IOC设计思想~~)

public static void main(String[] args) throws IOException {
        JiehunImpl proxy = new JiehunImpl();

        //这个地方不能直接返回JiehunProxy这个类,要返回实现的接口
        JiehunInterface jp = (JiehunInterface) Proxy.newProxyInstance(o.getClass().getClassLoader(), proxy.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
                System.out.println("$proxy0代理类:帮忙布置婚礼会场");
                Object invoke = method.invoke(proxy, args);
                System.out.println("$proxy0代理类:收取代理干活费用");
                return invoke;
            }
        });
        jp.jiehundongzuo();

        generateClassFile(proxy.getClass(), jp.getClass().getSimpleName());
    }

其实也可以不写JiehunImpl类,直接new一个JiehunInterface接口,只不过必须重写其接口方法的实现,看着太乱而已.

追了半天源码,有个贼精辟的地方 ProxyGenerator.classgenerateProxyClass()方法:

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }

里面有个核心方法generateClassFile()点进去看源码:

private byte[] generateClassFile() {
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }

        Iterator var11 = this.proxyMethods.values().iterator();

        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }

        Iterator var15;
        try {
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();

            while(var11.hasNext()) {
                var12 = (List)var11.next();
                var15 = var12.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    this.methods.add(var16.generateMethod());
                }
            }

            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }

        if (this.methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        } else if (this.fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
            this.cp.getClass(dotToSlash(this.className));
            this.cp.getClass("java/lang/reflect/Proxy");
            var1 = this.interfaces;
            var2 = var1.length;

            for(var3 = 0; var3 < var2; ++var3) {
                var4 = var1[var3];
                this.cp.getClass(dotToSlash(var4.getName()));
            }

            this.cp.setReadOnly();
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);

            try {
                var14.writeInt(-889275714);
                var14.writeShort(0);
                var14.writeShort(49);
                this.cp.write(var14);
                var14.writeShort(this.accessFlags);
                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                var14.writeShort(this.interfaces.length);
                Class[] var17 = this.interfaces;
                int var18 = var17.length;

                for(int var19 = 0; var19 < var18; ++var19) {
                    Class var22 = var17[var19];
                    var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                }

                var14.writeShort(this.fields.size());
                var15 = this.fields.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                    var20.write(var14);
                }

                var14.writeShort(this.methods.size());
                var15 = this.methods.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                    var21.write(var14);
                }

                var14.writeShort(0);
                return var13.toByteArray();
            } catch (IOException var9) {
                throw new InternalError("unexpected I/O Exception", var9);
            }
        }

总结为就是:通过反射拿到JiehunImpl实现类的所有method和field进行遍历,并生成构造方法,生成了一个新的class文件,并写入到内存和磁盘中。好牛逼啊好牛逼,越过了java文件,直接生成class文件,真不愧是虚拟机(总感觉不是在夸他~~)

效仿源码中的方法,重新生成一遍class文件,并存储在本地,生成方法generateClassFile()的实现:

public static void generateClassFile(Class clazz, String proxyName) throws IOException {
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, new Class[]{clazz}, 0x00000010);
        String paths = clazz.getResource(".").getPath();
        System.out.println("paths:" + paths);
        FileOutputStream out = null;
        try{
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(proxyClassFile);
            out.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            out.close();
        }
    }

成功生成到本地目录:

SPRING-AOP之动态代理,核心原理深入理解

用dj-gui反编译$Proxy0.class并打开查看源码:

import com.spring.jiehun.JiehunImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy implements JiehunImpl {
  private static Method m1;
  
  private static Method m10;
  
  private static Method m2;
  
  private static Method m4;
  
  private static Method m5;
  
  private static Method m3;
  
  private static Method m7;
  
  private static Method m6;
  
  private static Method m9;
  
  private static Method m11;
  
  private static Method m0;
  
  private static Method m8;
  
  public $Proxy0(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 error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void notify() {
    try {
      this.h.invoke(this, m10, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final String toString() {
    try {
      return (String)this.h.invoke(this, m2, null);
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void jiehunHou1() {
    try {
      this.h.invoke(this, m4, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void jiehunHou2() {
    try {
      this.h.invoke(this, m5, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void jiehundongzuo() {
    try {
      this.h.invoke(this, m3, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void wait(long paramLong) throws InterruptedException {
    try {
      this.h.invoke(this, m7, new Object[] { Long.valueOf(paramLong) });
      return;
    } catch (Error|RuntimeException|InterruptedException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void wait(long paramLong, int paramInt) throws InterruptedException {
    try {
      this.h.invoke(this, m6, new Object[] { Long.valueOf(paramLong), Integer.valueOf(paramInt) });
      return;
    } catch (Error|RuntimeException|InterruptedException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final Class getClass() {
    try {
      return (Class)this.h.invoke(this, m9, null);
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void notifyAll() {
    try {
      this.h.invoke(this, m11, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final int hashCode() {
    try {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void wait() throws InterruptedException {
    try {
      this.h.invoke(this, m8, null);
      return;
    } catch (Error|RuntimeException|InterruptedException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  static {
    try {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m10 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("notify", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("jiehunHou1", new Class[0]);
      m5 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("jiehunHou2", new Class[0]);
      m3 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("jiehundongzuo", new Class[0]);
      m7 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("wait", new Class[] { long.class });
      m6 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("wait", new Class[] { long.class, int.class });
      m9 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("getClass", new Class[0]);
      m11 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("notifyAll", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m8 = Class.forName("com.spring.jiehun.JiehunImpl").getMethod("wait", new Class[0]);
      return;
    } catch (NoSuchMethodException noSuchMethodException) {
      throw new NoSuchMethodError(noSuchMethodException.getMessage());
    } catch (ClassNotFoundException classNotFoundException) {
      throw new NoClassDefFoundError(classNotFoundException.getMessage());
    } 
  }
} 

一目了然,全都是通过反射调用的。实现了JiehunImpl类的所有的方法,必然也实现了JiehunInterface()中的方法,所以生成的$Proxy0类不能强转为JiehunImpl类,只能强转其实现的接口类JiehunInterface。

本文地址:https://blog.csdn.net/jbb0403/article/details/108255245

相关标签: java 反射