`
技术无涯苦作舟
  • 浏览: 12190 次
社区版块
存档分类
最新评论

关于JDK动态代理

阅读更多
最近重温了下JDK动态代理,JDK1.8里的底层实现有了些变化,这里记录下看到的东西。
大家都知道,JDK动态代理只能为接口创建代理实例,所以CGLib就自然而然的有了用武之地。至于为什么JDK只能为接口创建代理实例,后面在说。要用到JDK动态代理,那InvocationHandler和Proxy这对神雕侠侣肯定是要到场的。

先写一个简单的JDK动态代理例子。

1. 一个UserService接口:
public interface UserService {
    void service();
}


2. 一个UserService接口的实现类UserServiceImpl:
public class UserServiceImpl implements UserService {

    public void service() {
        System.out.println("service() is running....");
    }
}


3. 自定义一个MyInvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
    //目标对象
    Object target;
    //通过构造函数传入希望被代理的目标对象并实例化
    public MyInvocationHandler(Object target){
        this.target = target;
    }
    //利用InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法将横切逻辑与业务逻辑编织在一起
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //模拟横切逻辑
        System.out.println("Start recording........");
        //业务逻辑, 并传入目标实例
        Object object = method.invoke(target, args);
        //模拟横切逻辑
        System.out.println("End recording........");
        //最后返回
        return object;
    }
}


4. 通过Proxy结合MyInvocationHandler来创建代理实例。
public class myProxyTest {
    @Test
    public void test(){
        //希望被代理的目标对象
        UserService userService = new UserServiceImpl();
        //创建InvocationHandler实例, 将横切逻辑与业务逻辑编织在一起
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
        //根据编织了横切逻辑与业务逻辑的InvocationHandler实例,创建代理实例
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                myInvocationHandler);
        //调用代理实例,和调用接口实例的方式一样
        proxy.service();
    }
}


测试结果为:
Start recording........
service() is running....
End recording........


用起来不难,但是要理解。之前说到,为什么JDK只能为接口创建代理实例,这里通过Proxy.newProxyInstance()的第2个参数可以看到Class<?>[] interfaces,只能是接口。

看看创建代理实例的源码:
a. 先看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);
        }

        /*
         * Look up or generate the designated proxy class. 查找或者生成指定的代理对象。
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        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;
                    }
                });
            }
//得到代理类的实例并传入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);
        }
    }



b.接着看getProxyClass0,这里非常清楚地写着如果proxy class已经存在,则直接从缓存中返回,否则通过ProxyClassFactory创建。
/**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }


c. 接着看返回的proxyClassCache,以下是初始化。创建proxy class需看ProxyClassFactory();

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


d.接下来看ProxyClassFactory,重点看看关键部分。
注释
/**
     * A factory function that generates, defines and returns the proxy class given
     * the ClassLoader and array of interfaces.
     */
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>{...}


实现方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            
            //省略部分代码.......

            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 + ".";
            }

            /*
             * Choose a name for the proxy class to generate.定义类名
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.这里生成ProxyClass的字节码文件。
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
            //这里通过defineClass0, 利用proxy 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(proxyName, interfaces,accessFlags);

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
//三个参数分别是var0: proxyName, var1: interfaces, var2: accessFlags
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
//动态生成代理类的字节码
        final byte[] var4 = var3.generateClassFile();
        if(saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                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;
    }


以上就是代理类如何动态生成的,包括代理类字节码在什么时候生成。下面我们要得到这个字节码,进行反编译来看看里面到底有何神秘。

5.写个类来得到生成的代理类字节码
public class GetGenerateClassFile {
    public static void getGenerateClassFile(String path){
//根据希望被代理的目标对象生成一个名为$Proxy1的代理类字节码,代理类名字格式是这样的: proxyClassNamePrefix = "$Proxy";
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass("$Proxy1", UserServiceImpl.class.getInterfaces());
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(path);
            fileOutputStream.write(proxyClassFile);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


然后在myProxyTest中调用上面的静态方法,得到代理类字节码文件。
public void GenerateProxyClassFile(){
        GetGenerateClassFile.getGenerateClassFile("C:/$Proxy1.class");
    }


6.进行反编译,直接用IDEA打开这个字节码文件,得到如下的类:
public final class $Proxy1 extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
//构造函数 传入InvocationHandler,实际上就是myInvocationHandler
    public $Proxy1(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 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);
        }
    }
//这里就是调用invoke(Object proxy, Method method, Object[] args)的地方。

    public final void service() throws  {
        try {
            super.h.invoke(this, m3, (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")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.smart.myProxy.UserService").getMethod("service", 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());
        }
    }
}


其实这里也看得出来代理类是继承的Proxy,由于JAVA没有多重继承,所以JDK的动态代理只能用于接口。这里真正说明了为什么只能为接口创建代理实例。
public final class $Proxy1 extends Proxy implements UserService 
分享到:
评论

相关推荐

    关于jdk动态代理的源码剖析

    ### 关于JDK动态代理的源码剖析 #### 一、引言 在Java开发过程中,动态代理技术是一项非常实用的技术,它可以帮助我们实现在不修改原有代码的基础上为方法增加额外的功能,比如日志记录、权限校验等。本文将深入...

    JDK动态代理_JDK动态代理

    ### JDK动态代理详解 #### 一、引言 在软件工程中,代理模式是一种常见的设计模式,它通过为一个对象提供一个替代品或占位符来控制对这个对象的访问。这种模式通常用于添加额外的功能(例如日志记录、事务管理等)...

    浅谈JDK动态代理与CGLIB代理去区别

    本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中的选择。 首先,JDK动态代理主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。Proxy类用于创建一个代理对象...

    Spring框架中JDK动态代理和cglib动态代理

    Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...

    jdk动态代理技术详解

    JDK 动态代理技术详解 JDK 动态代理技术是 Java 语言自身对动态代理的支持,类似于 JDK 中在 java.util 包中提供 Observable 类和 Observer 接口提供对观察者模式的语言级支持。动态代理的优点是可以动态地为软件...

    JDK动态代理源码

    在Java编程领域,JDK动态代理是一个非常重要的概念,它允许我们在运行时动态地创建一个实现了特定接口的代理对象,以此来拦截并扩展原有对象的行为。动态代理在很多场景下都有应用,比如AOP(面向切面编程)、事件...

    JDK动态代理简单示例

    JDK动态代理是Java编程中一个非常重要的特性,它允许我们在运行时创建具有特定接口的代理类实例。这种技术在很多场景下都非常有用,比如在AOP(面向切面编程)中实现方法拦截、日志记录、事务管理等。下面我们将深入...

    jdk 的动态代理和CGLIB代理

    jdk 的动态代理和CGLIB代理

    JDK动态代理 spring aop 的原理

    在Java编程领域,JDK动态代理是实现动态创建代理对象的一种技术,它是Java标准库提供的一种强大工具。Spring AOP(面向切面编程)则是一种流行的应用框架,它利用动态代理来实现对业务代码的切面增强,如日志、事务...

    AOP之JDK动态代理和CGLib动态代理

    Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...

    jdk动态代理和CGlib动态代理

    JDK动态代理和CGlib动态代理是Java中实现这一目标的两种主要方式。 ### JDK动态代理 JDK动态代理基于Java的接口实现。如果一个类实现了至少一个接口,我们就可以为这个类创建一个动态代理。动态代理通过`java.lang....

    java代理机制 JDK动态代理和cglib代理 详解

    本文将深入探讨两种主要的Java代理实现:JDK动态代理和CGLIB代理。 一、JDK动态代理 JDK动态代理基于接口实现,它要求被代理的类必须实现至少一个接口。在运行时,Java会动态地创建一个新的类,这个类实现了与原始...

    代理模式,JDK动态代理,SpringAOP来龙去脉

    在Java中,我们可以使用JDK的动态代理或者Spring AOP来实现代理模式。 JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。Proxy类是生成代理对象的工厂,而...

    JDK动态代理和CGLIB代理

    JDK动态代理和CGLIB代理是两种常用的实现方式。 首先,我们来看看JDK动态代理。JDK动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象...

    spring jdk动态代理

    Spring AOP允许我们通过代理来实现横切关注点,如日志、事务管理等,而JDK动态代理则是Spring AOP实现的一种方式。本文将深入探讨Spring如何利用JDK动态代理技术来实现这一功能,并通过实例解析其底层实现。 首先,...

    Jdk动态代理和cglib动态代理原理

    - **CGLIB代理**适用于目标类没有接口或者不希望修改原有接口的情况,其性能通常优于JDK代理,因为它是基于字节码生成的子类,而JDK代理需要反射调用接口方法。 在实际开发中,如Spring AOP框架就同时支持JDK和...

    java jdk 动态代理 演示demo

    Java JDK 动态代理是一种强大的特性,它允许我们在运行时创建代理对象,这些代理对象可以扩展或增强已存在的接口实现。动态代理在处理AOP(面向切面编程)场景、事件监听、性能监控等方面有着广泛的应用。下面我们将...

    模拟JDK动态代理内部实现

    在本文中,我们将深入探讨如何模拟JDK的动态代理内部实现。 首先,我们需要了解JDK动态代理的基础知识。Java中的动态代理通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口实现。`Proxy...

    CGLIB 和 JDK生成动态代理类的区别

    CGLIB和JDK动态代理是两种常用的实现方式,它们各有优缺点,适用于不同的场景。下面将详细探讨这两种动态代理的区别。 首先,JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect....

Global site tag (gtag.js) - Google Analytics