【Java】JDK动态代理实现原理

java,jdk · 浏览次数 : 2

小编点评

**JDK动态代理的原理** JDK中的动态代理机制是通过动态生成代理类来实现的,动态代理类继承了原始类,并在创建实例之前调用目标类的构造方法,并将目标类的实例返回。 **ProxyClassFactory类** ProxyClassFactory是一个内部类,用于动态生成代理类。它重写了apply方法,用于生成代理类。在apply方法中,它使用ProxyGenerator类动态生成代理类。 **ProxyGenerator类** ProxyGenerator类负责动态生成代理类。它使用反射技术动态生成代理类,并将代理类生成到指定的类文件中。 **代理类的生成** 当创建代理类时,ProxyGenerator类首先获取目标类的字节码,然后使用ProxyGenerator.generateClassFile()方法生成代理类的字节码。字节码会被保存在指定的位置中,并在运行代理类时加载到内存中。 **代理类的实例化** 当创建代理类时,调用其构造方法,并将目标类的实例作为参数传递给构造方法。构造方法调用InvocationHandler的invoke()方法,在invoke方法中调用目标类的execute()方法。 **代理类的执行** 当调用代理类的execute()方法时,实际上调用的是InvocationHandler的invoke()方法。InvocationHandler将执行目标类的execute()方法。 **代理类的生命周期** 代理类会在创建后自动被垃圾回收。当代理类的构造方法执行完毕时,InvocationHandler会被释放。当代理类被垃圾回收时,其字节码也会被垃圾回收。

正文

代理模式
代理模式一般包含三个角色:

  1. Subject:主题对象,一般是一个接口,定义一些业务相关的基本方法。
  2. RealSubject:具体的主题对象实现类,它会实现Subject接口中的方法。
  3. Proxy:代理对象,里面包含一个RealSubject的引用,外部会通过这个代理对象,来实现RealSubject中方法的调用。

JAVA中提供了动态代理的实现,需要依赖InvocationHandler

举个例子

Subject

首先创建一个主题对象,里面定义一个execute方法:

public interface Subject {
    void execute();
}

RealSubject

接着创建具体的主题对象实现类,它会实现Subject的方法

public class RealSubject implements Subject {
    @Override
    public void execute() {
        System.out.println("realsubject方法执行");
    }
}

创建InvocationHandler

JDK动态代理需要依赖InvocationHandler,所以这里创建一个ProxyInvocationHandler实现它的invoke方法,并提供了getProxy方法来获取创建的代理对象,ProxyInvocationHandler类中引用了需要代理的目标对象,也就是RealSubject,在invoke方法中通过反射执行了RealSubject中的方法:

public class ProxyInvocationHandler implements InvocationHandler {

    /**
     * 代理的目标对象,也就是RealSubject
     */
    private Object target;

   /**
     * 构造函数
     */
    public ProxyInvocationHandler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始执行方法:" + method.getName());
        // 通过反射执行RealSubject中的方法
        Object result = method.invoke(target, args);
        System.out.println("结束执行方法:" + method.getName());
        return null;
    }

    public Object getProxy() {
        // 创建代理对象,传入了类加载器、要代理对象的接口、InvocationHandler(this当前对象)
        return Proxy.newProxyInstance(Thread.currentThread()
                        .getContextClassLoader(), target.getClass().getInterfaces(), this);
    }
}

测试:

public class ProxyTest {
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 创建实际的对象
        Subject subject = new RealSubject();
        // 创建InvocationHandler,这里传入的真是对象
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(subject);
        // 获取代理对象
        Subject proxy = (Subject) invocationHandler.getProxy();
        // 执行方法
        proxy.execute();
    }
}

运行结果:

开始执行方法:execute
realsubject方法执行
结束执行方法:execute

根据输出结果,可以看出JDK动态代理,主要是通过InvocationHandler生成一个代理对象,通过这个代理对象可以执行目标方法,执行之时,首先会进入到InvocationHandler中的invoke方法,在创建InvocationHandler时
传入了实际的对象RealSubject,所以InvocationHandler中可以拿到真实对象,只需要在InvocationHandler中的invoke方法中通过反射执行RealSubject中对应的方法即可。

动态代理实现原理

在ProxyInvocationHandler中可以看到通过Proxy创建了一个代理对象,那么接下来就进入到Proxy中,看一下是如何创建代理对象的:

        // 创建代理对象,传入了类加载器、要代理对象的接口、InvocationHandler(this当前对象)
        return Proxy.newProxyInstance(Thread.currentThread()
                        .getContextClassLoader(), target.getClass().getInterfaces(), this);

Proxy

在Proxy中newProxyInstance方法创建代理对象的时候,传入了类加载器、需要代理的对象以及InvocationHandler:

  1. 根据类加载器和需要代理的对象接口信息生成代理对象的class;
  2. 根据生成的代理类的class信息,获取类的构造器;
  3. 通过构造器创建代理对象,并将InvocationHandler传入;
public class Proxy implements java.io.Serializable {
    // 创建代理对象
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) throws IllegalArgumentException {
        Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        // 1. 根据类加载器和需要代理的对象接口信息生成代理对象的class
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            // 2. 获取类构造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            // InvocationHandler
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // 3. 通过构造器创建代理对象,并将InvocationHandler传入
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
           //...
        }
    }
}
生成代理类的class

getProxyClass0中首先会进行边界检查,然后根据类加载器和需要代理的对象接口信息从缓存中获取生成的代理类的calss,具体的实现在WeakCache的get方法中:

   /**
     * 代理类的缓存
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * 生成代理类的class
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        // 边界检查
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
        // 从缓存proxyClassCache中获取class
        return proxyClassCache.get(loader, interfaces);
    }

   
WeakCache

WeakCache的get方法中如果根据缓存key获取对象为空,会创建一个Factory对象赋值给Supplier,Factory是WeakCache的一个内部类,它实现了Supplier接口,然后调用Supplier的get方法来生成代理类的class,接下来进入到Factory的get方法中:

final class WeakCache<K, P, V> {
    // 获取class
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);
        expungeStaleEntries();
        // 获取缓存key
        Object cacheKey = CacheKey.valueOf(key, refQueue);
        // 根据key获取对象
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        // 如果为空
        if (valuesMap == null) {
            // 创建一个ConcurrentMap
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
        // 创建subKey
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
        while (true) {
            if (supplier != null) {
                // 调用get方法获取class
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // 如果为空,创建Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
            // 如果supplier为null
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // 将factory赋值给supplier
                    supplier = factory;
                }
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
}
Factory

Factory是WeakCache的一个内部类,它实现了Supplier接口,在get方法中,又调用了valueFactory的apply方法创建class,valueFactory是WeakCache的一个成员变量,在WeakCache的构造函数中可以看到传入了valueFactory对象进行初始化,那么接下来就需要回到Proxy类中,看一下如何实例化WeakCache的:

final class WeakCache<K, P, V> {
    
    private final BiFunction<K, P, V> valueFactory;
    
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        // 初始化
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }

    // Factory
    private final class Factory implements Supplier<V> {

        private final K key;
        private final P parameter;
        private final Object subKey;
        private final ConcurrentMap<Object, Supplier<V>> valuesMap;

        Factory(K key, P parameter, Object subKey,
                ConcurrentMap<Object, Supplier<V>> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

        @Override
        public synchronized V get() { 
            // 
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
                return null;
            }
            
            V value = null;
            try {
                // 调用valueFactory的apply方法创建class
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            
            ......
              
            return value;
        }
    }
}
ProxyClassFactory

Proxy中WeakCache初始化的时候使用的是ProxyClassFactory类型的factory:

public class Proxy implements java.io.Serializable {  
     /**
     * WeakCache初始化
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
}

所以调用valueFactory的apply方法的时候会进入到ProxyClassFactory的apply方法,在apply方法中会通过ProxyGenerator动态生成代理类并加载类,然后将实例化的代理类返回:

 private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // 前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            ......

            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 生成代理类
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                // 加载代理,并返回对象
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                
                throw new IllegalArgumentException(e.toString());
            }
        }
    }
ProxyGenerator

ProxyGenerator是Proxy的一个内部类,用于动态生成class:

 private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {  
      public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        // 生成class
        final byte[] var4 = var3.generateClassFile();
        // 是否保存到文件,如果开启了之后,运行程序之后会在包下面生成class文件
        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), new String[0]);
                            Files.createDirectories(var3, new FileAttribute[0]);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class", new String[0]);
                        }

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

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

  1. 它继承了Proxy并实现了Subject,并且在构造函数中需要传入InvocationHandler对象;
  2. 当执行$Proxy0中的execute方法时,实际上调用的是InvocationHandler的invoke方法;

package com.sun.proxy;

import com.example.demo.bean.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

// 动态生成了一个$Proxy0类,它继承了Proxy并实现了Subject
public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    // 传入InvocationHandler对象
    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})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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);
        }
    }
    
    // Subject的execute方法
    public final void execute() throws  {
        try {
            // 调用了InvocationHandler的invoke方法
            super.h.invoke(this, m3, (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)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.example.demo.bean.Subject").getMethod("execute", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

总结

JDK的动态代理实现原理是在运行中动态生成代理类,这个代理类实现了Subject接口,在对代理类进行实例化的时候,需要传入InvocationHandler,当调用代理类的方法时,会执行InvocationHandler的invoke方法,在invoke方法中再执行真正的目标方法,从而完成代理功能。

参考

【拉勾教育】Dubbo源码解读与实战-代理模式与常见实现

与【Java】JDK动态代理实现原理相似的内容:

【Java】JDK动态代理实现原理

代理模式 代理模式一般包含三个角色: Subject:主题对象,一般是一个接口,定义一些业务相关的基本方法。 RealSubject:具体的主题对象实现类,它会实现Subject接口中的方法。 Proxy:代理对象,里面包含一个RealSubject的引用,外部会通过这个代理对象,来实现RealSu

[转帖]linux 部署jmeter&报错处理

一、linux 安装jdk Java Downloads | Oracle 二、 linux上传jmeter 2.1 上传jmeter jmeter 下载地址: Apache JMeter - Download Apache JMeter 注意: 我先在我本地调试脚本(mac环境),调试完成后,再在

ADB命令快速入门

什么是ADB adb的全称为Android Debug Bridge,就是起到调试桥的作用。通过adb我们可以方便调试Android程序。 环境搭建 1需要java环境: 安装完JDK需要配置环境变量: JAVA_HOME::JDK的安装目录 PATH:%JAVA_HOME%\bin;%JAVA_H

Java21上手体验-分代ZGC和虚拟线程

一、导语 几天前Oracle刚刚发布了Java21, 由于这是最新的LTS版本,引起了大家的关注。 我也第一时间在个人项目中进行了升级体验。 一探究竟,和大家分享。 二、Java21更新内容介绍 官方release公告: https://jdk.java.net/21/release-notes 开

[转帖]020 Linux 20 个宝藏命令案例

https://my.oschina.net/u/3113381/blog/5478108 1 JDK 相关的查找命令 (1)确认是否安装 JDK //命令 java -version //输出示例 openjdk version "1.8.0_212" OpenJDK Runtime Enviro

[转帖]JVM底层原理之标配参数、X和XX参数

一、JVM的参数类型 (1)标配参数(以-开头) java -version java -help java -showversion 在JDK各个版本之间稳定,很少有大的变化。 [标准VM参数表] 参数名称描述默认值-d32使用 32 位数据模型 (如果可用)/-d64使用 64 位数据模型 (如

[转帖]用实力诠释细节!“Java性能调优六大工具”之JDK命令行工具

https://www.zhihu.com/people/javajia-gou-ji-zhu-44/posts JDK命令行工具 在JDK的开发包中,除了大家熟知的java.exe和javac.exe外,还有一系列辅助工具。这些辅助工具位于JDK安装目录下的bin目录中,可以帮助开发人员很好地解决

千呼万唤始出来 JDK 21 LTS, 久等了

平地起惊雷!!! 目录英雄的迟暮大人时代变了JDK 21 LTS 前 JAVA并发编程模型JDK 21 LTS 中的 JAVA 并发编程模型虚拟线程 VS 线程池The Last 你可以称呼它为:JDK 8 之后的神,它也是很多人认为的 JDK 8 之后,最值得升级的版本。 以前大家都说: 他发任他

[转帖]毕昇 JDK:为啥是ARM 上超好用的 JDK

https://zhuanlan.zhihu.com/p/379175713 本文分享自华为云社区《【云驻共创】毕昇 JDK:“传奇再现”华为如何打造 ARM 上最好用的 JDK?》,原文作者:白鹿第一帅。 前言 不知道大家是否听说过亦或是使用过毕昇 JDK,是否从事 Java 工作?是否从事 JV

万字详解JVM,让你一文吃透

摘要:本文将带大家详细地了解关于JVM的一些知识点。 本文分享自华为云社区《【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列》,作者: 冰 河 。 JDK 是什么? JDK 是用于支持 Java 程序开发的最小环境。 Java 程序设计语言 Java 虚拟机 Java API类库 J