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

这篇具有很好参考价值的文章主要介绍了【Java】JDK动态代理实现原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

  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中对应的方法即可。
【Java】JDK动态代理实现原理

动态代理实现原理

在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:
【Java】JDK动态代理实现原理

  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源码解读与实战-代理模式与常见实现文章来源地址https://www.toymoban.com/news/detail-710795.html

到了这里,关于【Java】JDK动态代理实现原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。 静态代理 是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建

    2024年02月11日
    浏览(37)
  • 3_代理模式(动态代理JDK原生和CGLib)

    1.概念 代理模式(Proxy Pattern )是指 为其他对象提供一种代理,以控制对这个对象的访问 ,属于结构型模式。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 使用代理模式主要有两个目的: 一是保护目标

    2024年01月17日
    浏览(26)
  • 【深度思考】聊聊JDK动态代理原理

    首先,定义一个接口: 然后,新增一个类并实现上面的接口: 假设现在有这么一个需求:在不改动以上类代码的前提下,对该方法增加一些前置操作或者后置操作。 接下来就来讲解下,如何使用 JDK动态代理 来实现这个需求。 首先,自定义一个调用处理器,实现 java.lang.r

    2023年04月17日
    浏览(29)
  • 【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?

    Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别? 一、Java动态代理的实现 1、使用JDK Proxy实现动态代理 2、使用CGLib实现动态代理 二、JDK Proxy 与 CGLib 的区别 三、Spring中的动态代理 四、 Lombok代理原理 总结 本文深入探讨了Java动态代理的实现机制,分别介绍了使用JDK

    2024年03月14日
    浏览(34)
  • JDK 动态代理(Spring AOP 的原理)(面试重点)

            也叫委托模式.定义:为其他对象提供⼀种代理以控制对这个对象的访问.它的作⽤就是通过提供⼀个代理类,让我们 在调⽤⽬标⽅法的时候,不再是直接对⽬标⽅法进⾏调⽤,⽽是通过代理类间接调⽤,在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,⽽代

    2024年01月22日
    浏览(30)
  • java中的静态代理、jdk动态代理以及CGLIB 动态代理

    代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能 那以下文章主要谈三种代理模式, 分别是静态代理,jdk的动态代理,cglib的动

    2024年02月11日
    浏览(34)
  • Java——JDK动态代理

    动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益的最大化,此时就可以请律师帮助自己不仅完成对案件的陈述

    2024年02月09日
    浏览(25)
  • Java代理之jdk动态代理+应用场景实战

    本文将先介绍jdk动态代理的基本用法,并对其原理和注意事项予以说明。之后将以两个最常见的应用场景为例,进行代码实操。这两个应用场景分别是 拦截器 和 声明性接口 ,它们在许多开发框架中广泛使用。比如在spring和mybatis中均使用了拦截器模式,在mybatis中还利用动态

    2023年04月10日
    浏览(29)
  • [Java]静态代理、动态代理(基于JDK1.8)

    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18002823 出自【进步*于辰的博客】 参考笔记一,P83;笔记二,P75.4。 目录 1、概述 2、静态代理的两种形式 2.1 面向接口 2.2 面向继承 3、动态代理的两种形式 3.1 JDK动态代理

    2024年03月09日
    浏览(28)
  • Spring学习(五):一篇讲清楚动态代理(jdk和cglib)的使用、原理和源码

    目录 一、jdk动态代理的基本使用 二、cglib动态代理的基本使用 2.1 方法一:method.invoke() 方法反射调用 2.2 方法二(spring使用的这个方法): methodProxy.invoke() 2.3 方法三:methodProxy.invokeSuper() 三、jdk实现代理的原理  四、jdk实现代理的源码 五、jdk对代理的优化  六、cglib实现动

    2023年04月14日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包