Java动态代理详解,以及底层JDK源码实现分析(基于Java8)。

java 动态代理模式在框架中大量得到了使用。动态代理也是学习Spring原理的基础。

所以我们相当有必要学习好这一设计模式。

对于动态代理有两种实现,一种是JDK自带的实现,还有一种是cglib库的实现。

这里笔者分析的是JDK自带的实现,以及JDK源码底层是如何做到的。


好,说了半天,动态代理到底是个什么东西呢?

代理即想找某个人,但是我们无法真正的联系到他,但是可以通过中介的方式联系到。

相当于租房子。你只能通过中介联系到房东。并且,你需要付给中介一定的费用。

这就是一个现实生活中的代理模式。


好,想知道原理我们首先要知道怎么去使用动态代理模式。

这里笔者写一个非常简单的demo,相信广大的朋友看了就立刻会明白其中的意思。

上代码。

package dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 契约接口
 */
interface Goal
{
    void doSomething();
}

/**
 * 被代理的类
 */
class RealGoal implements Goal
{
    @Override
    public void doSomething()
    {
        System.out.println( "做某事......" );
    }
}

public class DynamicProxyDemo implements InvocationHandler
{
    /**
     * 被代理的对象
     */
    private RealGoal realGoal ;
    
    public DynamicProxyDemo(RealGoal realGoal)
    {
        this.realGoal = realGoal;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        /**
         * 做真正的目的时,我们可以在之前或之后加入一点我们的代理类想要做的事情
         */
        System.out.println("做某事之前");
        realGoal.doSomething();
        System.out.println("做某事之后");
    
        return null;
    }
    
    
    public static void main(String[] args)
    {
        /**
         * new 一个被代理的对象
         */
        RealGoal myRealGoal = new RealGoal();
    
        Class<?> clazz = myRealGoal.getClass();
    
        /**
         * 得到代理对象(以前笔者都认为拿到的是真实的目标对象,其实不是,这里拿到的是代理对象,而且是java在我们运行时给我们定义好的类相当于 public class  $Proxy0定义了$Proxy0这么一个类 )
         * $Proxy0这个类继承了  java.lang.reflect.Proxy,并且实现了被代理类所实现的所有接口.
         * 从newProxyInstance()方法第二个参数中我们可以看出来。
         */
        Goal goal = (Goal) Proxy.newProxyInstance( clazz.getClassLoader(), clazz.getInterfaces(), new DynamicProxyDemo( myRealGoal ) );
    
        goal.doSomething();
    
    }
    
}

执行结果是在  做某事的前后加上了一句 做某事之前和做某事之后。

前后打印的两句话是额外加上去的,即证明不是直接调用的目标对象里的方法。

这里有的朋友可能会问了?

为何我没有看到代理类的定义呢?

那是因为代理类是在运行的过程中定义的。相当于运行的时候 public class $Proxy0 定义了这么一个对象。


产生代理对象的是这行代码。 

Goal goal = (Goal) Proxy.newProxyInstance( clazz.getClassLoader(), clazz.getInterfaces(), new DynamicProxyDemo( myRealGoal ) );

想要知道底层源码实现,我们可以进去看一看实现过程。

源码的讲解我都在注释里面去讲了。


package java.lang.reflect;

import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
import sun.misc.ProxyGenerator;
import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;


public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * 自己实现的一个InvocationHandler对象。在生成Proxy的子类的时候会被赋值上
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }

    /**
     * 在生成Proxy子类的时候,子类的构造方法会有一行这样的代码。
        super(h);其中h为实现了InvocationHandler接口的对象
     */
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }
    

   
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //判断实现的接口是否超过65535
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

       
        //从缓存中拿代理类的Class对象,这里实现的过程比较复杂,笔者略过,不做讨论。
        return proxyClassCache.get(loader, interfaces);
    }

    /*
     * a key used for proxy class with 0 implemented interfaces
     */
    private static final Object key0 = new Object();

    /*
     * Key1 and Key2 are optimized for the common use of dynamic proxies
     * that implement 1 or 2 interfaces.
     */

    /*
     * a key used for proxy class with 1 implemented interface
     */
    private static final class Key1 extends WeakReference<Class<?>> {
        private final int hash;

        Key1(Class<?> intf) {
            super(intf);
            this.hash = intf.hashCode();
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf;
            return this == obj ||
                   obj != null &&
                   obj.getClass() == Key1.class &&
                   (intf = get()) != null &&
                   intf == ((Key1) obj).get();
        }
    }

    /*
     * a key used for proxy class with 2 implemented interfaces
     */
    private static final class Key2 extends WeakReference<Class<?>> {
        private final int hash;
        private final WeakReference<Class<?>> ref2;

        Key2(Class<?> intf1, Class<?> intf2) {
            super(intf1);
            hash = 31 * intf1.hashCode() + intf2.hashCode();
            ref2 = new WeakReference<Class<?>>(intf2);
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf1, intf2;
            return this == obj ||
                   obj != null &&
                   obj.getClass() == Key2.class &&
                   (intf1 = get()) != null &&
                   intf1 == ((Key2) obj).get() &&
                   (intf2 = ref2.get()) != null &&
                   intf2 == ((Key2) obj).ref2.get();
        }
    }

    /*
     * a key used for proxy class with any number of implemented interfaces
     * (used here for 3 or more only)
     */
    private static final class KeyX {
        private final int hash;
        private final WeakReference<Class<?>>[] refs;

        @SuppressWarnings("unchecked")
        KeyX(Class<?>[] interfaces) {
            hash = Arrays.hashCode(interfaces);
            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {
                refs[i] = new WeakReference<>(interfaces[i]);
            }
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            return this == obj ||
                   obj != null &&
                   obj.getClass() == KeyX.class &&
                   equals(refs, ((KeyX) obj).refs);
        }

        private static boolean equals(WeakReference<Class<?>>[] refs1,
                                      WeakReference<Class<?>>[] refs2) {
            if (refs1.length != refs2.length) {
                return false;
            }
            for (int i = 0; i < refs1.length; i++) {
                Class<?> intf = refs1[i].get();
                if (intf == null || intf != refs2[i].get()) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * A function that maps an array of interfaces to an optimal key where
     * Class objects representing interfaces are weakly referenced.
     */
    private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }

    //这是代理类工厂类
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        
        //定义的名字前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 生成的数,跟在$Proxy这个名字之后,你会发现,动态代理类的名字都是 $ProxyN (N=0,1,2,3,4,5,6,7,8)
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

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

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
               
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                
                //判断Class对象是否代表的是一个接口
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }

               
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            
            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) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

    
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        /*
            要求h非空,否则抛出空指针异常
        */
        Objects.requireNonNull(h);

        //克隆一份被代理目标类所实现所有接口的 Class对象数组
        final Class<?>[] intfs = interfaces.clone();

        /*中间省略一些代码*/


        //拿到代理类的Class对象
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * 中间忽略了一些代码
         */
       
            //拿到代理类的Constructor对象,以便用于构造代理对象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //判断访问修饰符
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //返回构造的代理类对象,这里留个意,传入的是 实现了InvocationHandler接口的对象
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

  

   
    
    //根据字节数组生成代理类的Class对象
    private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);
}

有的人问了,那么那么InvocationHandler的invoke()方法是由谁调用的呢?又是什么时候调用的呢?


这里笔者让产生的动态代理类保存到了硬盘上已.class 结尾的文件。

运行这段代码即可

package dynamicProxy;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;

public class ProxyGeneratorUtils
{
    /**
     * 把代理类的字节码写到硬盘上
     */
    public static void writeProxyClassToHardDisk(String path)
    {
        
        
        // 获取代理类的字节码  方法的第二个参数为被代理类所实现的全部接口
        byte[] classFile = ProxyGenerator.generateProxyClass( "$Proxy11", RealSubject.class.getInterfaces() );
        
        FileOutputStream out = null;
        
        try
        {
            out = new FileOutputStream( path );
            out.write( classFile );
            out.flush();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                out.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
    }
}
得到动态代理对象时候,使用反编译工具我们可以查看 $Proxy0这个类的源码。

这里笔者反编译的结果是这样的

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import dynamicProxy.Goal;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy11 extends Proxy implements Goal {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    /*
    这里的构造方法说明了先调用了父类Proxy的构造方法,吧实现了InvocationHandler的对象设置上。

    */
    public $Proxy11(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);
        }
    }

    /*从这个方法中我们可以看出InvocationHandler对象的invoke世界上是由Proxy的子类------>运行时动态生成的类来调用的
        并且索要的所有参数,都是从这个动态代理的类中传入的。 
    */
    public final void doSomething() 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)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }


        /*
    
        我们可以看到在这个反编译的类中,static代码块拿到了反射API  Method  。 这个Method即为InvocationHandler里的method对象。
再有一个
        */
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("dynamicProxy.Goal").getMethod("doSomething", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", 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());
        }
    }
}




所有的讲解都写在了代码的注释里面.


另外在附上图片一张,对照着里面的代码,你会对动态代理有一个更深更次的认识。


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值