Spring源码深度解析(郝佳)-学习-jdk动态代理

tech2022-11-06  97

今天我们来了解一下jdk动态代理 jdk动态代理是基于接口实现

Person.java

public interface Person { public void findLove(); }

Customer.java

public class Customer implements Person { @Override public void findLove() { System.out.println(" 高富帅 180米 "); } }

JDKMeipo.java

public class JDKMeipo implements InvocationHandler { private Object target; public Object getInstance(Object target) throws Exception { this.target = target; Class<?> clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是媒婆,我要给你物色对象,现在已经确认你的需求了,开始物色"); Object obj = method.invoke(this.target, args); System.out.println("如果合适的话,就准备办事"); return null; } }

测试

@Test public void test2() throws Exception { Person obj = (Person) new JDKMeipo().getInstance(new Customer()); obj.findLove(); byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class}); FileOutputStream os = new FileOutputStream("/Users/quyixiao/project/spring_tiny/src/main/java/com/spring_101_200/test_101_110/test110_jdk_proxy/$Proxy0.class"); os.write(bytes); os.close(); }

生成的代理类代码如下: $Proxy0.class

import com.spring_101_200.test_101_110.test110_jdk_proxy.Person; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Person { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void findLove() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.spring_101_200.test_101_110.test110_jdk_proxy.Person").getMethod("findLove"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }

【运行结果 】 我是媒婆,我要给你物色对象,现在已经确认你的需求了,开始物色 高富帅 180米 如果合适的话,就准备办事

方法实现目的很简单,就是想在findLove方法前和方法后打印一条记录 结果正如预期那样。 我们新建一个代理类JDKMeipo实现InvocationHandler ,并且实现invoke方法,在invoke方法中,我们通过反射机制调用Customer的findLove方法,为什么这样可以呢? this.target 毫无疑问的是传递进来的new Customer()对象,因为findLove没有参数,所以args 为null ,那么method方法是如何来的呢?我们看看$Proxy0.class ,在里面有一个这样的代理方法。

public final void findLove() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }

在这个方法中,它调用了super.h 是调用父类Proxy的InvocationHandler 实例, 而在下面代码中,将JDKMeipo对象传递给了InvocationHandler对象 所以在动态代理类中的super.h.invoke(this, m3, (Object[])null);这一行中实际调用的是JDKMeipo的invoke方法,同时传递m3 方法到invoke方法中,我们看看动态代理类$Proxy.class 中的m3 是如何来的

m3 = Class.forName("com.spring_101_200.test_101_110.test110_jdk_proxy.Person").getMethod("findLove");

m3 实际是获取到了Person类的findLove方法,而在JDKMeipo通过反射从而调用到了Customer的findLove方法。 调用关系图如图所示

$Proxy.class 是如何生成的呢?目前还没有研究, 以后有时间,再来补这个块的内容了。

本文学的github地址是 https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_101_200/test_101_110/test110_jdk_proxy

最新回复(0)