JDK的动态代理

JDK的动态代理,使用最经典的应该是spring AOP,默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现(具体可看Spring AOP的实现).
通过JDK的动态代理,可以为任意的JAVA对象创建代理对象.

下面我们看一个简单的demo:

//被代理的对象,也就是目标对象
public interface ProxyService {
    public void printContent();
}
public class ProxyServiceImpl implements ProxyService {
    @Override
    public void printContent() {
        System.out.println("I am the target object's method!");
    }
}



public class DynamicProxyHandler implements InvocationHandler {

    public Object target;//目标对象

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

    /**
     * 执行目标对象的方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在目标对象的方法执行之前简单的打印一下
        System.out.println("------------------before------------------");

        // 执行目标对象的方法
        Object result = method.invoke(target, args);

        // 在目标对象的方法执行之后简单的打印一下
        System.out.println("-------------------after------------------");

        return result;
    }


    /**
     * 获取目标对象的代理对象
     * @return 代理对象
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}


public class DynamicProxyDemo {

    public static void main(String[] args) {
    //这行代码的作用下文会解释
     System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 
        ProxyService proxyService = new ProxyServiceImpl();
        System.out.println(proxyService.getClass());
        DynamicProxyHandler handler = new DynamicProxyHandler(proxyService);
        ProxyService proxy =  (ProxyService)handler.getProxy();
        System.out.println(proxy.getClass());
        proxy.printContent();

    }

}

输出结果:

class dynamicProxy.ProxyServiceImpl
class com.sun.proxy.$Proxy0
------------------before------------------
I am the target object's method!
-------------------after------------------

从上面可以看出,JDK的动态代理使用起来非常简单,但是看起来又很让人很费解,下面我们看一下Proxy源码中的newProxyInstance方法


@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);
    }
    //生成代理对象的类
    Class<?> cl = getProxyClass0(loader, intfs);
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        // 调用代理对象的构造方法
        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;
                }
            });
        }
        // 生成代理类的实例,参数是DynamicProxyHandler对象
        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);
    }
}

下面再进getProxyClass方法看一下

 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //代理的接口数量不能超过65535
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
// JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理  
        return proxyClassCache.get(loader, interfaces);
    }

我们可以在proxyClassCache.get()的具体方法中发现,没有缓存的代理类是通过ProxyClassFactory的apply方法创建

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

   // 用于生成代理类名字的计数器($Proxy0、$Proxy1、$Proxy2……)
    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");
            }
            //验证是接口
            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;

        /*
         * 对于非公共接口,代理类的包名与接口的相同
         * 对公共接口,代理类的包默认为com.sun.proxy
         */
        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();
        //类名 com.sun.proxy.$Proxy0,com.sun.proxy.$Proxy1……
        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());
        }
    }
}

下面看一下ProxyGenerator的generateProxyClass方法

private static final boolean saveGeneratedFiles = ((Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();

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), 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来会生成的class保存到本地,代码如下:





<div class="se-preview-section-delimiter"></div>

```java
 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 

生成class文件路径:
此处输入图片的描述

下面看一下class文件内容:

//继承Proxy,由于Java不能多继承的特性导致了JDK代理只能代理接口的原因(类是有CGLIB代理实现的)
public final class $Proxy0 extends Proxy implements ProxyService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    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})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void printContent() 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 {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("dynamicProxy.ProxyService").getMethod("printContent", 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());
        }
    }
}

通过上面的class文件我们可以知道,代理对象是通过DynamicProxyHandler的invoke方法来调用ProxyService接口中的printContent方法,到这里整个代理过程就完了。

代码地址:JDK动态代理demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值