JDK动态代理实现原理及手写JDK动态代理

1.JDK动态代理原理分析

  1. 在使用jdk动态代理的时候,必须要实现InvocationHandler接口,invoke方法Invoke 方法中该三个参数分别表示为: 代理对象、被代理执行的方法、参数
  2. 使用jdk动态代理获取代理类对象(JDK自动生成代理类) $Proxy0.class

  3. 将生成代理类加载至内存,让该类变成可执行类

2.源码分析

这里查看JDK1.8.0_191的源码,通过debug学习JDK动态代理的实现原理

首先我们当然是进入到Proxy的静态方法newProxyInstance中,代码附带注解如下:


@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{ 
    // 判断InvocationHandler是否为空,若为空,抛出空指针异常
    Objects.requireNonNull(h);
    //克隆接口的Class引用数组
    final Class[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     *生成接口的代理类的字节码文件
     */
    Class cl = getProxyClass0(loader, intfs);

    /*
     *使用自定义的InvocationHandler作为参数,调用构造函数获取代理类对象实例
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //获取构造器
        final Constructor cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        //若代理类不是public修饰,取消构造器的访问权限限制
        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);
    }
}

这个方法还是挺简单的,就是先生成一个代理类的Class引用,然后通过调用Class引用中的构造方法来实例化一个代理对象,其中的关键的代码就是如何获取代理类一个Class引用,让我们进入方法getProxyClass0

    private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        //限定代理的接口不能超过65535个
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // 若缓存中已经存在代理类的副本则直接返回,否则它将通过代理工厂类来创建代理类
        return proxyClassCache.get(loader, interfaces);
    }

该方法中的proxyClassCache对象的声明如下所示,其中的ProxyClassFactory代码会在后面贴出来

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

通过代码查看proxyClassCache.get()方法:

    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

    //通过上面生成的key来获取对应的value,其中value是一个map存的是上面用来实例化proxyClassCache的KeyFactory和ProxyClassFactory

        ConcurrentMap> valuesMap = map.get(cacheKey);
    //若valueMap为null则初始化,若map中有旧的valueMap则赋值给valueMap
        if (valuesMap == null) {
            ConcurrentMap> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

    //创建KeyFactory对象,并用此对象来获取提供代理类的对象
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier supplier = valuesMap.get(subKey);
    //提供代理类对象的工厂

        Factory factory = null;

        while (true) {
        //若supplier不为null,则获取代理类
            if (supplier != null) {
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }


        //若factory为null则实例化一个
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

        //若supplier为空则赋值为factory并存到valueMap中
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
            //若替换成功则将supplier负责为factory,否则直接赋值为valueMap中存储的对象
                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);
                }
            }
        }
    }

通过 V value = supplier.get()代码后可以看出关键的代码在与supplier对象的get方法和如何实例化出来的一个代理工厂类对象,让我们继续来看下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;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

        @Override
        public synchronized V get() { // serialize access
            // re-check
            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 {
                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;
        }
    }

通过value = Objects.requireNonNull(valueFactory.apply(key, parameter))代码中我们只需要关注get方法中的valueFactory对象的apply方法,该方法才是用来生成代理类的Class对象,代码如下:

private static final class ProxyClassFactory
        implements BiFunction[], Class>
    {
        // 代理类的类名的前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 代理类的编号,防止代理类名一致,通过原子类实现
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

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

            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            //遍历接口数组
            for (Class intf : interfaces) {
                //验证类加载器中是否存在该接口的一个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");
                }
                //判断是否是接口
                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;     
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            //验证是否存在不是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");
                    }
                }
            }

            if (proxyPkg == null) {
                //如果没有非公共的接口,则包名使用com.sun.proxy
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            //代理类的名称
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            //生成代理类的字节码文件
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //通过字节码文件生成一个代理类的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());
            }
        }
    }

上述代码中defineClass0是一个本地方法,可以将字节码文件生成我们需要的Class对象,而ProxyGenerator的generateProxyClass方法是用来生成字节码文件:


    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;
    }

最终生成代理类:

public final class $Proxy0 extends Proxy implements OrderService {
    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 test() 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 void service() throws  {
        try {
            super.h.invoke(this, m4, (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);
        } 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("com.dylan.proxy.service.OrderService").getMethod("test");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.dylan.proxy.service.OrderService").getMethod("service");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可看到

1、代理类继承了Proxy类并且实现了要代理的接口,由于java不支持多继承,所以JDK动态代理不能代理类

2、重写了equals、hashCode、toString

3、有一个静态代码块,通过反射或者代理类的所有方法

4、通过invoke执行代理类中的目标方法doSomething

3.手写JDK动态代理

JDK动态代理实现原理及手写JDK动态代理_第1张图片

3.1JavaClassLoader

public class JavaClassLoader extends ClassLoader {
    private File classPathFile;
    public final static String CLASS_PATH = "/Users/wangqingfang/Desktop/ideaSpace/ext_proxy/src/main/java/com/dylan/ext/jdk/";

    public JavaClassLoader() {
        this.classPathFile = new File(CLASS_PATH);
    }


    /**
     * 实现生成class文件并直接家在至内存
     *
     * @param name 文件名称该文件由extProxy动态生成
     * @return
     */
    @Override
    public Class findClass(String name) {
        String className = JdkProxy.PROXY_PACKAGE + "." + name;
        if (classPathFile != null) {
            File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
            if (classFile.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                    /**ps:该方法直接会将生成的class文件加载至内存*/
                    return defineClass(className+"", out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

3.2ExtJdkInvocationHandler接口

public interface ExtJdkInvocationHandler {
    /**
     * 动态代理对方法进行插入
     *
     * @param proxy  由jdk动态生成代理类@see JdkProxy.java
     * @param method 通过代理需要调用的目标方法
     * @param args   目标方法携带参数
     * @return
     * @throws Throwable
     */
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

}

3.3JdkProxy

public class JdkProxy {
    /**
     * 代码换行
     */
    private final static String RT = "\r\t";
    /**
     * 生成java文件位置
     */
    public static final String PROXY_PACKAGE = "com.dylan.ext.jdk";
    /**
     * 生成class类名称
     */
    private static final String proxyClassNamePrefix = "$Proxy";
    /**
     * 原子类 保证代理类的唯一性
     */
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    /**
     * 动态生成代理类 暂不实现多个实现类情况
     *
     * @param loader
     * @param classInfo
     * @param h
     * @return
     * @throws IllegalArgumentException
     */
    public static Object newProxyInstance(JavaClassLoader loader,
                                          Class classInfo,
                                          ExtJdkInvocationHandler h)
            throws IllegalArgumentException {
        String className = doClassPackage(classInfo);
        javaCompilerClassInfo(className);
        //4.使用classClassLoader 将$Proxy0.class读取到内存中...
        Class classProxy = loader.findClass(className);
        try {
            //5.使用java反射机制给函数中赋值
            Constructor m = classProxy.getConstructor(ExtJdkInvocationHandler.class);
            Object o = m.newInstance(h);
            return o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 对生成的java文件字符拼接
     *
     * @param classInfo
     * @return
     */
    public static String doClassPackage(Class classInfo) {
        if (null == classInfo) {
            throw new RuntimeException("Necessary parameter classInfo can`t be null");
        }
        Method[] methods = classInfo.getMethods();
        String className = getClassNameInfo();
        String proxyClass = "package " + PROXY_PACKAGE + ";" + RT
                + "import java.lang.reflect.Method;" + RT
                + "import java.lang.reflect.Method;" + RT
                + "import com.dylan.ext.jdk.handler.ExtJdkInvocationHandler;" + RT
                + "public class " + className + " implements " + classInfo.getName() + "{" + RT
                + "ExtJdkInvocationHandler h;" + RT
                + "public "+className+"(ExtJdkInvocationHandler h)" + "{" + RT
                + "this.h= h;" + RT + "}"
                + getMethodString(methods, classInfo) + RT + "}";
        writeProxy(className, proxyClass);

        return className;
    }

    /**
     * 获取class类名称
     *
     * @return
     */
    public static String getClassNameInfo() {
        return proxyClassNamePrefix + nextUniqueNumber;
    }

    /**
     * 生成代理方法
     *
     * @param methods
     * @param classInfo
     * @return
     */
    public static String getMethodString(Method[] methods, Class classInfo) {
        String proxyMe = "";
        for (Method method : methods) {
            Parameter[] parameters = method.getParameters();
            proxyMe += "public void " + method.getName() + "() throws Throwable {" + RT
                    + "Method md= " + classInfo.getName() + ".class.getMethod(\"" + method.getName()
                    + "\",new Class[]{});" + RT
                    + "this.h.invoke(this,md,null);" + RT + "}" + RT;

        }
        return proxyMe;
    }

    /**
     * 将动态生成代理类写入到指定位置
     *
     * @param filename
     * @param proxyClass
     */
    public static void writeProxy(String filename, String proxyClass) {
        /**此处应对filename proxyClass 进行合法性验证和非空验证*/
        FileWriter fw = null;
        try {
            File f = new File(JavaClassLoader.CLASS_PATH + filename+".java");
            fw = new FileWriter(f);
            fw.write(proxyClass);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fw.flush();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 使用JavaJavaCompiler 编译该$Proxy0源代码 获取class文件
     *
     * @param filename
     */
    public static void javaCompilerClassInfo(String filename) {
        /**此处应对filename  进行合法性验证和非空验证*/
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMgr = null;
        try {
            fileMgr = compiler.getStandardFileManager(null, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fileMgr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Iterable units = fileMgr.getJavaFileObjects(JavaClassLoader.CLASS_PATH + filename+".java");
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
        t.call();
    }

}

3.4OrderInvocationHandler

public class OrderInvocationHandler implements ExtJdkInvocationHandler {
    /**
     * 目标代理对象
     */
    public Object target;

    public OrderInvocationHandler(Object target) {
        this.target = target;
    }

    public OrderInvocationHandler() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        // 执行代理对象方法
        Object result = method.invoke(target, args);
        after();
        return result;
    }

    /**
     * 前置通知
     */
    private void before() {//方法执行前
        System.out.println("<<<<<<<<<<<<前置方法");
    }

    /**
     * 后置通知
     */
    private void after() {//方法执行后
        System.out.println("<<<<<<<<<<<<后置方法");
    }

    /**
     * 获取代理对象类以及将代理类加载到内存
     *
     * @param 
     * @return
     */
    public  T getProxy() {
        return (T) JdkProxy.newProxyInstance(new JavaClassLoader(), this.target.getClass(), this);
    }

    public static void main(String[] args) throws Throwable{
        OrderService orderService =(OrderService) JdkProxy.newProxyInstance(new JavaClassLoader(), OrderService.class, new OrderInvocationHandler(new OrderServiceImpl()));
        orderService.service();
    }
}

3.4OrderService及实现OrderServiceImpl

public interface OrderService {

    /**
     * 订单操作
     *
     * @throws Throwable
     */
    void service() throws Throwable;

}
public class OrderServiceImpl implements OrderService {

    @Override
    public void service() {
        System.out.println("执行了订单操作。。。。。。。。");
    }
}

3.5运行后得到代理类

package com.dylan.ext.jdk;

import java.lang.reflect.Method;
import java.lang.reflect.Method;

import com.dylan.ext.jdk.handler.ExtJdkInvocationHandler;

public class $Proxy0 implements com.dylan.ext.jdk.service.OrderService {
    ExtJdkInvocationHandler h;

    public $Proxy0(ExtJdkInvocationHandler h) {
        this.h = h;
    }

    
    public void service() throws Throwable {
        Method md = com.dylan.ext.jdk.service.OrderService.class.getMethod("service", new Class[]{});
        this.h.invoke(this, md, null);
    }

}

3.6最终运行结果

JDK动态代理实现原理及手写JDK动态代理_第2张图片

你可能感兴趣的:(程序员)