JDK8动态代理实现与原理解析

第一部分:JDK8动态代理基本实现

1,先定义一个接口
public interface UserService {
    void work(String workContent);
}
2,再定义一个接口实现类
public class StudentService implements UserService {
    @Override
    public void work(String workContent) {
        System.out.println("StudentService work:" + workContent);
    }
}
3,定义最关键的InvocationHandler实现类
public class UserProxyHandler implements InvocationHandler {
    UserService realService;
    UserService proxyInstance;

    public UserProxyHandler(UserService userService) {
        realService = userService;
        //关键点1:代理实例生成
        proxyInstance = (UserService) Proxy.newProxyInstance(getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
    }

    public UserService getRealService() {
        return realService;
    }

    public UserService getProxyInstance() {
        return proxyInstance;
    }

     // 关键点2:代理实例的接口方法会调用InvocationHandler的invoke方法
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("UserProxyHandler before");
        // 代理实现的地方
        Object result = method.invoke(realService, objects);
        System.out.println("UserProxyHandler after");
        return result;
    }
}
4,调用代理类,观察代理过程
StudentService studentService = new StudentService();
UserProxyHandler userProxyHandler = new UserProxyHandler(studentService);
userProxyHandler.getProxyInstance().work("proxy go school");

输出结果:
在这里插入图片描述

结果分析

整个过程结果都看到,我们明明调用的是代理对象的work方法,但最终还是进入了UserProxyHandler的invoke方法,并通过代理层,调用了真实类的StudentService的work方法。

但是我们还是不清楚JDK到底是如何实现这一步的,其实重点就是2个问题:

  1. 代理对象是如何产生的
  2. InvocationHandler的invoke方法具体的怎么调用的

那就老老实实看源码

第二部分:JDK8动态代理原理解析

一,代理对象的产生过程

这部分基本就要看JDK8的源码了,直接IDEA上面一步步,看源码的实现过程,这里只分析重点代码。

Proxy.newProxyInstance方法

将该方法简化后,其实就做了三部:

  1. 得到代理类的Class对象
  2. 获得该Class对象的构造函数反射
  3. 调用构造函数反射生成对象
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,,InvocationHandler h) {
    Class<?> cl = getProxyClass0(loader, intfs);
    final Constructor<?> cons = cl.getConstructor(constructorParams);
	return cons.newInstance(new Object[]{h});
}

很明显,其中重要的就是第一步,jdk如何得到代理类的Class对象,
该Class对象的生成过程getProxyClass0()。

getProxyClass0()

然而,这个方法内部很简单。

private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        return proxyClassCache.get(loader, interfaces);
    }
proxyClassCache.get()
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

该方法主要是做了一层内存缓存。具体的Class生成过程其实在ProxyClassFactory里面

缓存过程分析:

get方法首先创建一个valuesMap,获取subKey,里面比较重要的就是subKeyFactory.apply(key,parameter),这个方法会帮我们生成代理类的subKey,之后会建立一个Factory,当使用Factory.get的时候,回去调用valueFactory.apply()
valueFactory即构造函数里面的ProxyClassFactory,便是真正生成代理类的时候。

缓存的思考:

由于第一次的时候需要动态的去创建字节码,然后进行加载,初始化,因此效率和直接new对象相比会比较低下。 这也是使用缓存的原因。虽然有缓存,但是由于使用了WeakReference,GC后有可能会被回收,那么就得重新加载,一定程度上会降低效率,所以一般情况下,我们尽量避免这种动态生成类的方式,而是用在编译时生成类的方式取代,这便是APT技术的精髓。

public V get(K key, P parameter) {
        Object cacheKey = CacheKey.valueOf(key, refQueue);
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                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
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
            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);
                }
            }
        }
    }
ProxyClassFactory.apply()

这里面主要五点,
1,利用Class.forName复制一份接口参数传入的接口Class对象
2,拼接Proxy的类名形为: xxx$Proxy0
3,代理类的accessFlags
4,ProxyGenerator.generateProxyClass()获得Class字节码
5,ProxyGenerator.defineClass0() 通过native调用加载字节码,获取Java层Proxy的Class对象

@Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                Class<?> interfaceClass = null;
                interfaceClass = Class.forName(intf.getName(), false, loader);
            }
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            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 + ".";
            }
            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
        }

至此,代理类的对象生成过程就彻底搞清楚了

二,InvocationHandler的invoke调用时机

我们大胆猜测,具体过程肯定都在ProxyGenerator.generateProxyClass()的生成过程中。
也就是里面的generateClassFile()方法中,此处代码没有注释,只能猜测着看
直接搜索InvocationHandler,很明显发现:
1, generateConstructor 生成了注入InvocationHandler的代理类构造函数

private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
        ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
        DataOutputStream var2 = new DataOutputStream(var1.code);
        this.code_aload(0, var2);
        this.code_aload(1, var2);
        var2.writeByte(183);
        var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
        var2.writeByte(177);
        var1.maxStack = 10;
        var1.maxLocals = 2;
        var1.declaredExceptions = new short[0];
        return var1;
    }

2,ProxyMethod.generateMethod 生成了调用InvocationHandler.invoke的代理接口方法(这里只展示部分代码)

private ProxyGenerator.MethodInfo generateMethod() throws IOException {
        String var1 = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);
        ProxyGenerator.MethodInfo var2 = ProxyGenerator.this.new MethodInfo(this.methodName, var1, 17);
        int[] var3 = new int[this.parameterTypes.length];
        int var4 = 1;
        for(int var5 = 0; var5 < var3.length; ++var5) {
            var3[var5] = var4;
            var4 += ProxyGenerator.getWordsPerType(this.parameterTypes[var5]);
        }
        byte var7 = 0;
        DataOutputStream var9 = new DataOutputStream(var2.code);
        ProxyGenerator.this.code_aload(0, var9);
        var9.writeByte(180);
	    var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
        ProxyGenerator.this.code_aload(0, var9);
        var9.writeByte(178);
        var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));
        if (this.parameterTypes.length > 0) {
            ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);
            var9.writeByte(189);
            var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));

            for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {
                var9.writeByte(89);
                ProxyGenerator.this.code_ipush(var10, var9);
                this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);
                var9.writeByte(83);
            }
        } else {
            var9.writeByte(1);
        }
        var9.writeByte(185);
        var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"));
        var9.writeByte(4);
        var9.writeByte(0);
}

我们可以调用ProxyGenerator.generateProxyClass来看一下这个生成的类,把它写到文件里,然后打开验证一下,关键方法如下所示:

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

至此,谜底全部解开了!!!

猜你喜欢

转载自blog.csdn.net/iamcodingmylife/article/details/89141012
今日推荐