JDK1.8动态代理示例及代理实现原理详解

概述

    该篇博客为对JDK代理的学习笔记,首先给出一段实现了jdk动态代理的代码和这段代码的运行结果,先有一个直观的感受。然后会根据执行流程介绍用到的类与方法,再分析产生的$Proxy0.class文件,最后结合前文总结出动态代理的一些特性,因为已经从源码的级别去看了动态代理,所以对动态代理的了解就会从知其然到知其所以然的境界。这是我的第一篇博客,格式布局暂时就这样了吧。

    欢迎转载,但请注明出处,毕竟写这么一篇还是需要花点时间的。



目录

  • 一:动态代理代码及运行结果
  • 二:newProxyInstance方法及InvocationHandler介绍
  • 三:生成代理对象流程分析    
  1.   newProxyInstance
  2.   getProxyClass0  
  3.   WeakCache
  4.   WeakCache.Factory
  5.   ProxyCalssFactory
  6.   Proxygenerator及gernateProxyClass
  7.   generateClassFile
  8.   keyFactory及key1
  • 四:保存代理对象字节码文件$Proxy0
  • 五:总结
  • 六:参考



  • 一:动态代理代码及运行结果

//目标对象需要实现的接口

package reflection.DynamicProxy;
public interface UserDao {
    void findUserByUserCode(String userCode);
    void findUserByEmai(String email);
}

//目标对象

package reflection.DynamicProxy;
public class UserDaoImpl implements UserDao {
    @Override
    public void findUserByUserCode(String userCode) {
        System.out.println("UserDaoImpl:findUserByUserCode");
    }

    @Override
    public void findUserByEmai(String email) {
        System.out.println("UserDaoImpl:findUserByEmai");
    }
}

//代理对象生成工厂

package reflection.DynamicProxy;
import java.lang.reflect.Proxy;

public class UserDaoImplProxyFactory {
    public UserDao getUserDaoImpl(UserDao target){
        UserDao proxy = (UserDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[]{UserDao.class}, (proxy1, method, args) -> {
            Object result;
            if(method.getName().equals("findUserByUserCode")){
                System.out.println("open transaction");
                result = method.invoke(target,args);
                System.out.println("close transaction");
            }else{
                result = method.invoke(target,args);
            }
            return result;
        });
        return proxy;
    }
}

//动态代理测试类:

package reflection.DynamicProxy;

import org.junit.Test;

public class TestDynamicProxy {
    @Test
    public static void main (String[] args){
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        UserDao userDaoImplProxy = new UserDaoImplProxyFactory().getUserDaoImpl(userDaoImpl);

        System.out.println("执行未动态代理方法:");
        userDaoImpl.findUserByUserCode("jack");
        System.out.println("执行动态代理方法:");
        userDaoImplProxy.findUserByUserCode("jack");
        userDaoImplProxy.findUserByEmai("xxx");
    }
}

运行结果为:

JDK1.8动态代理示例及代理实现原理详解_第1张图片

从结果中可以看到,通过代理对象调用方法实现了对该方法的增强,可以看到在方法的调用前后都执行了在代理类中添加的代码。同时因为在代理类中对要增强的方法名称进行了过滤,所以并没有对findUserByEmail方法进行增强,而是直接执行,效果与不进行代理相同。



  • 二:newProxyInstance方法及InvocationHandler介绍

接下来让我们来了解用到的类及API:

想要创建一个代理对象,需要使用java.lang.reflect.Proxy类的newProxyInstance方法。该方法定义为:

    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

  这三个参数的含义为:

  • 一个类加载器(关于类加载器的相关概念可以看:xxx(还未写,之后补上))
  • 一个Class对象数组,每个元素都是目标对象需要实现的接口
  • 一个调用处理器,即一个实现了InvocationHandler接口的对象。
在上面我们看到有一个参数为接口InvocationHandler,该接口的定义与规定需要实现的方法为:
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

我们可以看到该接口只有一个名为invoke的方法,这种只有一个方法的接口也叫做函数式接口,因为它可以用lambda表达式来实现。无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的调用参数。调用处理器必须给出处理调用的方式。这三个参数的含义为:

  • 目标对象,这个目标对象需要从外部传入。
  • Method对象,Methd是java.lang.reflect中的一个类,关于反射概念及java反射包的相关内容可以参考XXX(还未写,之后补上)。它代表内容其实就是我们想要调用的方法,概念就像是C中的函数指针一样,传入这个对象,然后这个对象代表的方法就会在invoke中执行,这样我们在外部用代理对象调用不同的方法,相应的这个方法对象就会传入到这,然后进行执行。
  • 最后一个参数即我们想要执行的方法的参数



  • 三:生成代理对象流程分析  

到这里,我们对需要用到类和API也有了一定了解,因为动态代理与反射的联系还是很密切的,所以要理解动态代理也需要对反射有一定认识,关于反射,可以通过上面的链接得到一个简单参考。现在来根据程序流程来看看,API都为我们做了哪些事情。

  1.   newProxyInstance
既然是利用newProxyInstance方法来进行代理的,那么我们就先看看newProxyInstance方法的源码:
    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);
        }

 	//关键部分:getProxyClass0返回或者新建一个代理类的Class对象
        Class cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
	    //关键部分:根据获得的代理类Class对象或代理类构造器
	    //构造器的参数定义为:private static final Class[] constructorParams = { InvocationHandler.class };
            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //关键部分:根据刚才获得构造器返回代理类实例对象,到这里已经完成了代理类的生成。
            //稍后将代理类实例用其实现的某个接口的接口引用指向这个对象,利用多态特性就调用了我们增强的方法
            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);
        }
    }

这个方法的源码还是很清晰的,因为我们最终的目的是获得代理类实例,所以newProxyInstance先调用了getProxyClass0来获得代理类的Class对象,然后获取其构造器对象,最通过构造器对象的newInstance方法构造除了一个代理类实例,并返回这个实例。

    2  .getProxyClass0  

上部分的关键是:getProxyClass0(loader,intfs);那我们再进入这个方法里面,看看它都干了什么事情

private static Class getProxyClass0(ClassLoader loader,
                                       Class... interfaces) {
    //目标对象实现的接口数不可超过65535个
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    //如果指定代理类类对象已经存在,就直接返回这个代理类类对象,否则就新建一个
    //proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    return proxyClassCache.get(loader, interfaces);
}

这个方法就更加精简了,就是调用proxyClassCache.get(loader,intetfaces)方法来获得代理类对象,这个proxyClassCache是一个WeakCacke类的实例,由名字可以知道,这是一个缓存,但为什么有个Weak,这是因为其缓存的机制是通过弱引用来实现的(关于弱引用等相关概念,可以参考XXX(还未写,之后补上))。因此我们需要看看这个WeakCache具有哪些成员变量,并且看看它的get是怎么实现的:

    3.WeakCache

final class WeakCache {
    //引用队列,这个结构体一般是和弱引用相关的,在这里就不详细说明了
    private final ReferenceQueue refQueue = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    //可以看出,一个Map嵌套了另一个Map,我们可以将其看作是二级缓存
    //就是说可以通过一个key获得一个Map对象,然后再利用subkey获得我们真正想要的对象
    //ConcurrentMap是一个线程安全的Map,关于其介绍可以参考xxx(还未写,以后补上)
    private final ConcurrentMap>> map
        = new ConcurrentHashMap<>();
    private final ConcurrentMap, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    //BiFunction 这是一个函数式接口, 只有一个apply方法,用于接收两个参数,返回一个值
    private final BiFunction subKeyFactory;
    private final BiFunction valueFactory;

    //要求传入的参数是BiFunction引用类型的,传入的实参是 new KeyFactory(), new ProxyClassFactory();我们将在后面介绍这两个类
    public WeakCache(BiFunction subKeyFactory,
                     BiFunction valueFactory) {
        //非空要求
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }
    
    //关键就在于这个方法,我们说的一级缓存的key其实是ClassLoader,二级缓存的subkey是实现的接口的Class对象数组,需要的值为代理类的Class对象
    //getProxyClass0调用语句为return proxyClassCache.get(loader, interfaces),可以看到key为ClassLoader,parameter为接口的Class对象数组
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();
	//将key也就是ClassLoader用弱引用缓存起来,得到一级缓存的cacheKey
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //由一级缓存的cacheKey来获得二级缓存的对象(又是一个Map对象,其中有subkey和我们需要的代理类的Classd对象)
        //Supplier也是一个函数式接口,有一个get方法,表示不需要参数,返回一个V类型的值,其实就是对代理类的Classd对象的包装
        ConcurrentMap> valuesMap = map.get(cacheKey);
        //确保用同一个key返回的是同一个value,包装并发下的正确性
        if (valuesMap == null) {
            //如果没有获得到二级缓存对象,就新建立一个空Map关联cachekey存入到Map中
            ConcurrentMap> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            //其余线程通过这个cachekey存入了个对象,那就取出来,用别的线程存进去的二级缓存对象
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
        
        //到此为止,我们获得了二级缓存对象,但是二级缓存对象里面到底有没有我们需要的键值对却不一定哦

        // create subKey and retrieve the possible Supplier stored by that
        // subKey from valuesMap
        //通过subKeyFactory来获得二级缓存的subkey,subKeyFactory就是刚才传入的KeyFactory,我们现在只用把它看作是接口的Class对象数组的弱引用就好
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //通过二级缓存的subkey来获得需要的对象 即代理类Class对象的封装类型,注意现在这个supplier可能为空,也可能不为空哦
        Supplier supplier = valuesMap.get(subKey);
        Factory factory = null;

	//进行轮询,直到获得代理类的Class对象
        while (true) {
        //注意:这里的supplier的含义发生了改变,它不仅仅代表了CacheValue(就是代理类的Class对象),还可能是可以生成代理类的Class对象Factory实例
        //这里需要与下面的代码结合起来看
        //终将从这里返回代理类的Class对象,缓存中有就是从CacheValue中去,缓存中没有就是从Factory中生成,所以我们又需要看Factory是什么样的啊
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue instance
                V value = supplier.get();  //简直就是关键中的关键啊
                //与subkey关联的对象里面确实封转了值的,获得到了Class对象,返回
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            //现在我们确定了,与接口的Class对象数组关联的弱引用(subkey)关联的代理类Class对象没有在缓存中,所以我们需要生成它
            //如果第一次轮询执行到这,是为空的,主要的目的就是新建一个Factory,而个类的作用就是生成代理类的Class对象
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

	    //没有任何对象和subkey关联的话,就把subkey和Factory关联,然后让supplier指向factory对象,就是为subkey关联一个工厂,这个工厂也有个get方法
	    //通过工厂的get方法也能返回我们需要的代理类Class对象
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
    //省略其余代码
    .........
}

从上面可以看出WeakCache是用Map包含一个二级缓存的,其结构概括为Map>,抛开弱引用的部分,在这里key是传入的ClassLoader,subkey是传入的interface的Class对象数组。有缓存的话直接返回代理类的Class对象,没有的话通过Factory类的get方法来产生指定的代理类的Class对象,因此,我们又来分析Factory对象吧,离最终理解代理机制不远了:

    4.WeakCache.Factory

private final class Factory implements Supplier {

        private final K key;   
        private final P parameter;
        private final Object subKey;
        private final ConcurrentMap> valuesMap;

        Factory(K key, P parameter, Object subKey,
                ConcurrentMap> valuesMap) {
            this.key = key;               //是传入的loader
            this.parameter = parameter;   //是传入的接口的Class对象数组
            this.subKey = subKey;         //与传入的接口关联的弱引用对象
            this.valuesMap = valuesMap;   //二级缓存对象
        }

        @Override
        public synchronized V get() { // serialize access
            // re-check
            //再次检查与subkey关联的Supplier是否为空,防止在多线程的情况下发生错误
            Supplier supplier = valuesMap.get(subKey);
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            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);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue cacheValue = new CacheValue<>(value);

            // put into reverseMap
            reverseMap.put(cacheValue, Boolean.TRUE);

            // try replacing us with CacheValue (this should always succeed)
            if (!valuesMap.replace(subKey, this, cacheValue)) {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
    }

可以看到整个Factory实际上做的事情就是调用valueFactory的appaly方法,我们应该还记得valueFactory是WeakCache的成员变量,在WeakCache的构造函数中将这个引用指向了一个ProxyClassFactory对象。根据这个对象的名字,可以猜出就是通过这个对象来产生代理类对象,简直迫不及待的想要看看它会做一些什么事情了:

    5.ProxyClassFactory

 private static final class ProxyClassFactory
        implements BiFunction[], 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) {
	    //IdentityHashMap是一种用==而不是用equals比较键值的映射表
            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            //循环处理给出的接口
            for (Class intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                 //验证用给定的类加载器通过接口名字解析给出的Class对象与传入的接口Class对象是否相同
                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");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                 //验证给出的接口Class对象数组中的每个元素确实是接口的Class对象
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                 //验证给出的接口Class对象不重复
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

	    //定义代理对象所在的包
            String proxyPkg = null;     // package to define proxy class in
            //重要:可以看到修饰符被设置为public和final
            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.
             */
             //重要:记录下修饰符不是public的接口所在的包并且验证是否所有的修饰符不为public的接口都处于同一个包中,
            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");
                    }
                }
            }
	    //如果所有的接口都是public修饰符,则代理类所在的包为com.sun.proxy
            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            //生成代理类的完整名字
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            //关键:生成表示代理类的Class对象的二进制
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
            	//defineClass0是一个本地方法,可以看出它是将字节数组生成代理类的Class对象,返回值就是我们需要的代理类Class对象
                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());
            }
        }
    }

可以看到这个类可以为代理对象的生成进行一些校验,并且目的对象及代理对象的一些特性也可以由这个类中的代码解释清楚了。但这个类最重要的还是对Proxygenerator类的gernateProxyClass方法的调用,正是由这个方法来生成我们需要的代理类的Class对象信息的。那肯定还是要去观摩这个类的:

     6.Proxygenerator与gernateProxyClass

  	//省略部分代码
  	.......
    private static final String superclassName = "java/lang/reflect/Proxy";
    private static final String handlerFieldName = "h";
    //是否将生成的字节码文件保存在本地标识
    private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
    private static Method hashCodeMethod;
    private static Method equalsMethod;
    private static Method toStringMethod;
    private String className;
    private Class[] interfaces;
    private int accessFlags;
    private ProxyGenerator.ConstantPool cp = new ProxyGenerator.ConstantPool();
    private List fields = new ArrayList();
    private List methods = new ArrayList();
    private Map> proxyMethods = new HashMap();
    private int proxyMethodCount = 0;
 
     //从调用这个方法的地方这三个参数的实参分别为 代理类Class文件名称,需要实现的接口,修饰符
    public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {
    	//设置传入的参数
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        //根据指定的信息生成字节码文件
        final byte[] var4 = var3.generateClassFile();
        //是否要保存字节码文件到本地
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction() {
                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));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

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

        return var4;
    }
    省略部分代码
    .........

可以看到在这个类中调用了生成字节码文件的最终方法,同时还可以根据参数来设置是否将代理类的字节码文件保存在本地,在之后会介绍如何设置这个参数,并分析生成的字节码文件。在现在还是先看看generateClassFile的实现代码:

       7.generateClassFile

    private byte[] generateClassFile() {
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }

        Iterator var11 = this.proxyMethods.values().iterator();

        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }

        Iterator var15;
        try {
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();

            while(var11.hasNext()) {
                var12 = (List)var11.next();
                var15 = var12.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    this.methods.add(var16.generateMethod());
                }
            }

            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }

        if (this.methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        } else if (this.fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
            this.cp.getClass(dotToSlash(this.className));
            this.cp.getClass("java/lang/reflect/Proxy");
            var1 = this.interfaces;
            var2 = var1.length;

            for(var3 = 0; var3 < var2; ++var3) {
                var4 = var1[var3];
                this.cp.getClass(dotToSlash(var4.getName()));
            }

            this.cp.setReadOnly();
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);

            try {
                var14.writeInt(-889275714);
                var14.writeShort(0);
                var14.writeShort(49);
                this.cp.write(var14);
                var14.writeShort(this.accessFlags);
                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                var14.writeShort(this.interfaces.length);
                Class[] var17 = this.interfaces;
                int var18 = var17.length;

                for(int var19 = 0; var19 < var18; ++var19) {
                    Class var22 = var17[var19];
                    var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                }

                var14.writeShort(this.fields.size());
                var15 = this.fields.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                    var20.write(var14);
                }

                var14.writeShort(this.methods.size());
                var15 = this.methods.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                    var21.write(var14);
                }

                var14.writeShort(0);
                return var13.toByteArray();
            } catch (IOException var9) {
                throw new InternalError("unexpected I/O Exception", var9);
            }
        }
    }

对于在这里面的方法就不在详细的去看了,我们已经达到我们的目的了,清楚了代理的整个调用流程,并对代理机制的底层代码实现有了一定深入的了解。但是还有一个对象我们提及过,却还没去了解其实现代码,那就是构造proxyClassCahe的参数keyFactory,我们来看看它,这样整个调用流程就算是走完整了:

    8.keyFactory及key1

    private static final class KeyFactory
        implements BiFunction[], 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);
            }
        }
    }
我们选取最常用的Key1看看里面是什么
    /*
     * a key used for proxy class with 1 implemented interface
     */
    private static final class Key1 extends WeakReference> {
        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();
        }
    }
这就是前文已经说过的subkey的具体含义。



  • 四:保存代理对象字节码文件$Proxy0

 在前文已经知道,可以通过设置参数来使生成的字节码文件保存在本地磁。上,这个参数为:

    “sun.misc.ProxyGenerator.saveGeneratedFiles”

在生成字节码文件之前需要我们在工作文件中添加包com.sun.proxy,至于为什么加这个包,源码已经告诉我们了。前提是需要实现的接口修饰符为public,这也可以在源码中找到答案。

参数设置可以通过配置虚拟机参数实现:

JDK1.8动态代理示例及代理实现原理详解_第2张图片

或者在代码中通过编码的方式设置参数:

JDK1.8动态代理示例及代理实现原理详解_第3张图片


生成这个文件后,我们利用java反编译的工具来看看其内部到底有什么玄机:

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

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import reflection.DynamicProxy.UserDao;

public final class $Proxy0 extends Proxy implements UserDao {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    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 findUserByEmai(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } 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);
        }
    }

    public final void findUserByUserCode(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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("reflection.DynamicProxy.UserDao").getMethod("findUserByEmai", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("reflection.DynamicProxy.UserDao").getMethod("findUserByUserCode", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

这个代理类有一个静态代码块,用于初始化函数对象,包括接口中的方法以及equals,toString,hashCode方法。

还可以看出$Proxy0继承了Proxy类,并且将传入的InvocationHandler对象传递给了Proxy,在Proxy中用变量h来接收,在执行方法的时候都是通过super.h.invoke(Object,args)的方式调用的。这个代理类理所当然的继承了给出的接口。



  • 五:总结

    至此,我们将JDK动态代理的实现及源码都过了一遍。所谓的动态代理实际上是生成一个代理对象,这个代理对象具有的方法为从Object继承来的方法和目标对象需要实现的接口里面规范出的方法。因为代理对象与目标对象都实现同样了接口,所有在程序中可以用某个特定的接口引用来执行它,这就用到多态的概念,在代理对象执行方法的时候其实是用调用它的超类Proxy的InvacationHander变量h的invoke方法来执行的,所以代理并不神秘。我认为其本质就是多态概念的运用。

    从源码中我们来总结以下动态代理的特点:

   1.代理类是在程序运行过程中创建的,一旦被创建,就变成了常规类,与虚拟机中其他类没有任何区别;

   2.所有的代理类都扩展Proxy类;

   3.所有的代理类都覆盖了Object类中的方法toString,equals,hashCode;

   4.代理类一定是public和final。如果代理类实现的所有接口都是public,代理类就不属于某个特定的包;否则,

      所有的非公共接口都必须属于同一个包,同时,代理类也属于这个包。

   5.代理类是通过接口来创建的一个新的类,与目标对象的唯一交集就在于它们必定有一个公共接口。



  • 六:参考    

   Java弱引用(WeakReference)的理解与使用点击打开链接

    深入理解ConcurrentMap.putIfAbsent(key,value) 用法:点击打开链接

    JDK动态代理实现原理:点击打开链接

    

    

你可能感兴趣的:(JavaSE)