ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【Java】JDK动态代理实现原理 [打印本页]

作者: 欢乐狗    时间: 2023-11-2 03:25
标题: 【Java】JDK动态代理实现原理
代理模式
代理模式一般包含三个角色:
JAVA中提供了动态代理的实现,需要依赖InvocationHandler
举个例子
Subject
首先创建一个主题对象,里面定义一个execute方法:
  1. public interface Subject {
  2.     void execute();
  3. }
复制代码
RealSubject
接着创建具体的主题对象实现类,它会实现Subject的方法
  1. public class RealSubject implements Subject {
  2.     @Override
  3.     public void execute() {
  4.         System.out.println("realsubject方法执行");
  5.     }
  6. }
复制代码
创建InvocationHandler
JDK动态代理需要依赖InvocationHandler,所以这里创建一个ProxyInvocationHandler实现它的invoke方法,并提供了getProxy方法来获取创建的代理对象,ProxyInvocationHandler类中引用了需要代理的目标对象,也就是RealSubject,在invoke方法中通过反射执行了RealSubject中的方法:
  1. public class ProxyInvocationHandler implements InvocationHandler {
  2.     /**
  3.      * 代理的目标对象,也就是RealSubject
  4.      */
  5.     private Object target;
  6.    /**
  7.      * 构造函数
  8.      */
  9.     public ProxyInvocationHandler(Object target){
  10.         this.target = target;
  11.     }
  12.     @Override
  13.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  14.         System.out.println("开始执行方法:" + method.getName());
  15.         // 通过反射执行RealSubject中的方法
  16.         Object result = method.invoke(target, args);
  17.         System.out.println("结束执行方法:" + method.getName());
  18.         return null;
  19.     }
  20.     public Object getProxy() {
  21.         // 创建代理对象,传入了类加载器、要代理对象的接口、InvocationHandler(this当前对象)
  22.         return Proxy.newProxyInstance(Thread.currentThread()
  23.                         .getContextClassLoader(), target.getClass().getInterfaces(), this);
  24.     }
  25. }
复制代码
测试:
  1. public class ProxyTest {
  2.     public static void main(String[] args) {
  3.         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  4.         // 创建实际的对象
  5.         Subject subject = new RealSubject();
  6.         // 创建InvocationHandler,这里传入的真是对象
  7.         ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(subject);
  8.         // 获取代理对象
  9.         Subject proxy = (Subject) invocationHandler.getProxy();
  10.         // 执行方法
  11.         proxy.execute();
  12.     }
  13. }
复制代码
运行结果:
  1. 开始执行方法:execute
  2. realsubject方法执行
  3. 结束执行方法:execute
复制代码
根据输出结果,可以看出JDK动态代理,主要是通过InvocationHandler生成一个代理对象,通过这个代理对象可以执行目标方法,执行之时,首先会进入到InvocationHandler中的invoke方法,在创建InvocationHandler时
传入了实际的对象RealSubject,所以InvocationHandler中可以拿到真实对象,只需要在InvocationHandler中的invoke方法中通过反射执行RealSubject中对应的方法即可。

动态代理实现原理

在ProxyInvocationHandler中可以看到通过Proxy创建了一个代理对象,那么接下来就进入到Proxy中,看一下是如何创建代理对象的:
  1.         // 创建代理对象,传入了类加载器、要代理对象的接口、InvocationHandler(this当前对象)
  2.         return Proxy.newProxyInstance(Thread.currentThread()
  3.                         .getContextClassLoader(), target.getClass().getInterfaces(), this);
复制代码
Proxy

在Proxy中newProxyInstance方法创建代理对象的时候,传入了类加载器、需要代理的对象以及InvocationHandler:
  1. public class Proxy implements java.io.Serializable {
  2.     // 创建代理对象
  3.     @CallerSensitive
  4.     public static Object newProxyInstance(ClassLoader loader,
  5.                                           Class<?>[] interfaces,
  6.                                           InvocationHandler h) throws IllegalArgumentException {
  7.         Objects.requireNonNull(h);
  8.         final Class<?>[] intfs = interfaces.clone();
  9.         final SecurityManager sm = System.getSecurityManager();
  10.         if (sm != null) {
  11.             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  12.         }
  13.         // 1. 根据类加载器和需要代理的对象接口信息生成代理对象的class
  14.         Class<?> cl = getProxyClass0(loader, intfs);
  15.         try {
  16.             if (sm != null) {
  17.                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
  18.             }
  19.             // 2. 获取类构造器
  20.             final Constructor<?> cons = cl.getConstructor(constructorParams);
  21.             // InvocationHandler
  22.             final InvocationHandler ih = h;
  23.             if (!Modifier.isPublic(cl.getModifiers())) {
  24.                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
  25.                     public Void run() {
  26.                         cons.setAccessible(true);
  27.                         return null;
  28.                     }
  29.                 });
  30.             }
  31.             // 3. 通过构造器创建代理对象,并将InvocationHandler传入
  32.             return cons.newInstance(new Object[]{h});
  33.         } catch (IllegalAccessException|InstantiationException e) {
  34.            //...
  35.         }
  36.     }
  37. }
复制代码
生成代理类的class

getProxyClass0中首先会进行边界检查,然后根据类加载器和需要代理的对象接口信息从缓存中获取生成的代理类的calss,具体的实现在WeakCache的get方法中:
  1.    /**
  2.      * 代理类的缓存
  3.      */
  4.     private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
  5.         proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  6.     /**
  7.      * 生成代理类的class
  8.      */
  9.     private static Class<?> getProxyClass0(ClassLoader loader,
  10.                                            Class<?>... interfaces) {
  11.         // 边界检查
  12.         if (interfaces.length > 65535) {
  13.             throw new IllegalArgumentException("interface limit exceeded");
  14.         }
  15.         // 从缓存proxyClassCache中获取class
  16.         return proxyClassCache.get(loader, interfaces);
  17.     }
  18.    
复制代码
WeakCache

WeakCache的get方法中如果根据缓存key获取对象为空,会创建一个Factory对象赋值给Supplier,Factory是WeakCache的一个内部类,它实现了Supplier接口,然后调用Supplier的get方法来生成代理类的class,接下来进入到Factory的get方法中:
  1. final class WeakCache<K, P, V> {
  2.     // 获取class
  3.     public V get(K key, P parameter) {
  4.         Objects.requireNonNull(parameter);
  5.         expungeStaleEntries();
  6.         // 获取缓存key
  7.         Object cacheKey = CacheKey.valueOf(key, refQueue);
  8.         // 根据key获取对象
  9.         ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  10.         // 如果为空
  11.         if (valuesMap == null) {
  12.             // 创建一个ConcurrentMap
  13.             ConcurrentMap<Object, Supplier<V>> oldValuesMap
  14.                 = map.putIfAbsent(cacheKey,
  15.                                   valuesMap = new ConcurrentHashMap<>());
  16.             if (oldValuesMap != null) {
  17.                 valuesMap = oldValuesMap;
  18.             }
  19.         }
  20.         // 创建subKey
  21.         Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  22.         Supplier<V> supplier = valuesMap.get(subKey);
  23.         Factory factory = null;
  24.         while (true) {
  25.             if (supplier != null) {
  26.                 // 调用get方法获取class
  27.                 V value = supplier.get();
  28.                 if (value != null) {
  29.                     return value;
  30.                 }
  31.             }
  32.             // 如果为空,创建Factory
  33.             if (factory == null) {
  34.                 factory = new Factory(key, parameter, subKey, valuesMap);
  35.             }
  36.             // 如果supplier为null
  37.             if (supplier == null) {
  38.                 supplier = valuesMap.putIfAbsent(subKey, factory);
  39.                 if (supplier == null) {
  40.                     // 将factory赋值给supplier
  41.                     supplier = factory;
  42.                 }
  43.             } else {
  44.                 if (valuesMap.replace(subKey, supplier, factory)) {
  45.                     supplier = factory;
  46.                 } else {
  47.                     // retry with current supplier
  48.                     supplier = valuesMap.get(subKey);
  49.                 }
  50.             }
  51.         }
  52.     }
  53. }
复制代码
Factory

Factory是WeakCache的一个内部类,它实现了Supplier接口,在get方法中,又调用了valueFactory的apply方法创建class,valueFactory是WeakCache的一个成员变量,在WeakCache的构造函数中可以看到传入了valueFactory对象进行初始化,那么接下来就需要回到Proxy类中,看一下如何实例化WeakCache的:
  1. final class WeakCache<K, P, V> {
  2.    
  3.     private final BiFunction<K, P, V> valueFactory;
  4.    
  5.     public WeakCache(BiFunction<K, P, ?> subKeyFactory,
  6.                      BiFunction<K, P, V> valueFactory) {
  7.         this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
  8.         // 初始化
  9.         this.valueFactory = Objects.requireNonNull(valueFactory);
  10.     }
  11.     // Factory
  12.     private final class Factory implements Supplier<V> {
  13.         private final K key;
  14.         private final P parameter;
  15.         private final Object subKey;
  16.         private final ConcurrentMap<Object, Supplier<V>> valuesMap;
  17.         Factory(K key, P parameter, Object subKey,
  18.                 ConcurrentMap<Object, Supplier<V>> valuesMap) {
  19.             this.key = key;
  20.             this.parameter = parameter;
  21.             this.subKey = subKey;
  22.             this.valuesMap = valuesMap;
  23.         }
  24.         @Override
  25.         public synchronized V get() {
  26.             //
  27.             Supplier<V> supplier = valuesMap.get(subKey);
  28.             if (supplier != this) {
  29.                 return null;
  30.             }
  31.             
  32.             V value = null;
  33.             try {
  34.                 // 调用valueFactory的apply方法创建class
  35.                 value = Objects.requireNonNull(valueFactory.apply(key, parameter));
  36.             } finally {
  37.                 if (value == null) { // remove us on failure
  38.                     valuesMap.remove(subKey, this);
  39.                 }
  40.             }
  41.             
  42.             ......
  43.               
  44.             return value;
  45.         }
  46.     }
  47. }
复制代码
ProxyClassFactory

Proxy中WeakCache初始化的时候使用的是ProxyClassFactory类型的factory:
  1. public class Proxy implements java.io.Serializable {  
  2.      /**
  3.      * WeakCache初始化
  4.      */
  5.     private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
  6.         proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  7. }
复制代码
所以调用valueFactory的apply方法的时候会进入到ProxyClassFactory的apply方法,在apply方法中会通过ProxyGenerator动态生成代理类并加载类,然后将实例化的代理类返回:
  1. private static final class ProxyClassFactory
  2.         implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  3.     {
  4.         // 前缀
  5.         private static final String proxyClassNamePrefix = "$Proxy";
  6.         // next number to use for generation of unique proxy class names
  7.         private static final AtomicLong nextUniqueNumber = new AtomicLong();
  8.         @Override
  9.         public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  10.             Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  11.             ......
  12.             long num = nextUniqueNumber.getAndIncrement();
  13.             String proxyName = proxyPkg + proxyClassNamePrefix + num;
  14.             /*
  15.              * 生成代理类
  16.              */
  17.             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  18.                 proxyName, interfaces, accessFlags);
  19.             try {
  20.                 // 加载代理,并返回对象
  21.                 return defineClass0(loader, proxyName,
  22.                                     proxyClassFile, 0, proxyClassFile.length);
  23.             } catch (ClassFormatError e) {
  24.                
  25.                 throw new IllegalArgumentException(e.toString());
  26.             }
  27.         }
  28.     }
复制代码
代理类的生成

由于设置了sun.misc.ProxyGenerator.saveGeneratedFiles为true,所以可以在包下面看到生成的代理类$Proxy0:

  1. private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {  
  2.       public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
  3.         ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
  4.         // 生成class
  5.         final byte[] var4 = var3.generateClassFile();
  6.         // 是否保存到文件,如果开启了之后,运行程序之后会在包下面生成class文件
  7.         if(saveGeneratedFiles) {
  8.             AccessController.doPrivileged(new PrivilegedAction<Void>() {
  9.                 public Void run() {
  10.                     try {
  11.                         int var1 = var0.lastIndexOf(46);
  12.                         Path var2;
  13.                         if(var1 > 0) {
  14.                             Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);
  15.                             Files.createDirectories(var3, new FileAttribute[0]);
  16.                             var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
  17.                         } else {
  18.                             var2 = Paths.get(var0 + ".class", new String[0]);
  19.                         }
  20.                         Files.write(var2, var4, new OpenOption[0]);
  21.                         return null;
  22.                     } catch (IOException var4x) {
  23.                         throw new InternalError("I/O exception saving generated file: " + var4x);
  24.                     }
  25.                 }
  26.             });
  27.         }
  28.         return var4;
  29.     }
  30. }
复制代码
总结
JDK的动态代理实现原理是在运行中动态生成代理类,这个代理类实现了Subject接口,在对代理类进行实例化的时候,需要传入InvocationHandler,当调用代理类的方法时,会执行InvocationHandler的invoke方法,在invoke方法中再执行真正的目标方法,从而完成代理功能。
参考
【拉勾教育】Dubbo源码解读与实战-代理模式与常见实现

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4