SPRING-AOP之动态代理 核心原理完全、深入、通透、准确的理解

最近在学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() {
                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之动态代理 核心原理完全、深入、通透、准确的理解_第1张图片

用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。

完美~

打完收工~

你可能感兴趣的:(java,反射)