Java8之动态代理

参考资料:

《Java动态代理分析》

《JAVA动态代理》

《Java 动态代理类》

写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

目录

一、代理模式

二、静态代理

三、动态代理

        1、动态代理的使用

        2、动态代理原理解析

        2.1、相关的类和接口

        2.2、动态代理步骤

        2.3、源码流程分析

补充

        1、代理类的存储

         2、代理类的类名

        3、类的继承关系


一、代理模式

        代理是一种常用的设计模式,其目的就是为真实对象提供一个代理对象以控制对真实对象的访问。代理类负责为委托类(被代理类、真实类)预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

这里写图片描述

         

        其实就是代理类为被代理类预处理消息、过滤消息并在此之后将消息转发给被代理类,之后还能进行消息的后置处理。代理类和被代理类通常会存在关联关系(即上面提到的持有的被带离对象的引用),代理类本身不实现服务,而是通过调用被代理类中的方法来提供服务。代理有两种模式,分别为静态代理与动态代理。

二、静态代理

        创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

// 接口
interface InterfaceA{
    void sayHello();
}

// 委托类
class ClassA implements InterfaceA{
    public void sayHello() {
        System.out.println("Hello ClassA");
    }
}

// 代理类
class ClassAProxy implements InterfaceA{
    private InterfaceA helloInterface = new ClassA();
    
    @Override
    public void sayHello() {
        System.out.println("Before invoke sayHello" );
        helloInterface.sayHello();
        System.out.println("After invoke sayHello");
    }
}

        委托类被传递给了代理类对象classAProxy,代理类在执行具体方法时通过所持用的被代理类完成调用。

    public static void main(String[] args)  {
        ClassAProxy classAProxy = new ClassAProxy();
        classAProxy.sayHello();
    }

         结果如下:

Before invoke sayHello
Hello ClassA
After invoke sayHello

        使用静态代理可以实现对一个已有类的拓展,但这样做较为繁琐,每次我们增加新的委托类就需要调整代理类,于是我们使用动态代理来减轻我们的工作量。

三、动态代理

        1、动态代理的使用

        利用反射机制在运行时创建代理类,接口、被代理类不变,我们构建一个handler类来实现InvocationHandler接口。

class ProxyHandler implements InvocationHandler{
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke "  + method.getName());
        method.invoke(object, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

         执行动态代理:

    public static void main(String[] args)  {
        // 创建委托类对象
        InterfaceA classa = new ClassA();
        // 创建调用处理器对象
        InvocationHandler handler = new ProxyHandler(classa);
        // 为指定类加载器,一组接口,调用处理器生成动态代理类对象
        InterfaceA proxyHello = (InterfaceA) Proxy.newProxyInstance(classa.getClass().getClassLoader(), classa.getClass().getInterfaces(), handler);
        // 代理类调用委托类真实方法
        proxyHello.sayHello();
    }

        通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例。针对不同的代理类,传入相应的代理程序控制器InvocationHandler。

        当我们要增加新的委托类时,只需要创建新的调用处理器对象即可。

interface InterfaceB {
    void sayBye();
}
class ClassB implements InterfaceB {
    @Override
    public void sayBye() {
        System.out.println("Bye zhanghao!");
    }
}
public static void main(String[] args)  {
        InterfaceA classa = new ClassA();
        InterfaceB classb = new ClassB();

        InvocationHandler handler = new ProxyHandler(classa);
        InvocationHandler handler2 = new ProxyHandler(classb);

        InterfaceA proxyHello = (InterfaceA) Proxy.newProxyInstance(classa.getClass().getClassLoader(), classa.getClass().getInterfaces(), handler);
        InterfaceB proxyBye = (InterfaceB) Proxy.newProxyInstance(classb.getClass().getClassLoader(), classb.getClass().getInterfaces(), handler2);

        proxyHello.sayHello();
        proxyBye.sayBye();
    }

        由此可见,动态代理简化了代理类的生成,减少了繁琐的静态代码编写。

        2、动态代理原理解析

        2.1、相关的类和接口

        (1)InvocationHandler

        调用处理器接口,它自定义了一个invoke方法,用于几种处理在动态代理类对象上的方法调用。通常在该方法中实现对委托类的代理访问。

public Object invoke(Object obj,Method method, Object[] args)

         第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

        (2)Proxy

        动态代理类,其中主要包含以下内容:

protected Proxy(InvocationHandler h)

        构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoaderloader, Class[] interfaces)

        获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)

        返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

        2.2、动态代理步骤

        (1)实现InvocationHandler接口,创建自己的调用处理器,重写invoke方法(可以根据自己的业务逻辑个性化);

        (2)通过为 Proxy 类指定ClassLoader对象和一组interface来创建动态代理类(分别为委托类的类加载器和所实现的接口,Proxy 静态方法生成动态代理类需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个.class 文件中。类加载器可以看我之前的文章《Java8之类的加载》);

        (3)通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

        (4)通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

        2.3、源码流程分析

        这部分源码较多,这里简要介绍下流程

        (1)Proxy.newProxyInstance调用getProxyClass0方法生成代理类对象,使用指定的调用处理程序(getConstructor方法)获取代理类的构造函数对象,获取Proxy Class构造函数,创建Proxy代理实例(cons.newInstance(new Object[]{h}))。

    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对象
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
            //其余代码
            //使用代理类的class对象获取代理类的构造函数对象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //如果Class作用域为私有,通过 setAccessible 支持访问
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //使用构造函数对象创建Proxy代理实例。
            return cons.newInstance(new Object[]{h});
            // 其余代码
    }

        (2)getProxyClass0尝试从缓存中获取代理类对象(proxyClassCache.get(loader, interfaces))。

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //如果接口数量大于65535,抛出非法参数错误
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
       
        //如果指定接口的代理类已经存在与缓存中,则不用新创建,直接从缓存中取即可;
        //如果缓存中没有指定代理对象,则通过ProxyClassFactory来创建一个代理对象。
        return proxyClassCache.get(loader, interfaces);
    }

        如没有则调用ProxyClassFactory来创建一个代理对象。 

    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }
    public V get(K key, P parameter) {
        //其余代码
        //尝试从缓存中获取代理类的class对象,如果没有则新建一个
        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;
            }
        }
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
        while (true) {
            //supplier在第二次循环时非空,进而调用内部类Factory的get方法
            if (supplier != null) {
                //调用内部类Factory的get方法
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            //这里factory首先会为空,然后新建一个factory,并在下方赋值给supplier
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    supplier = factory;
                }
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    supplier = factory;
                } else {
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

    private final class Factory implements Supplier<V> {
        @Override
        public synchronized V get() { // serialize access
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
                return null;
            }
            V value = null;
            try {
                // 调用valueFactory的apply方法
                //valueFactory即初始化时传进来的ProxyClassFactory
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { 
                    valuesMap.remove(subKey, this);
                }
            }
            assert value != null;
            CacheValue<V> cacheValue = new CacheValue<>(value);
            if (valuesMap.replace(subKey, this, cacheValue)) {
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }
            return value;
        }
    }

        (3)ProxyClassFactory为每个代理类设置前缀"$Proxy"+唯一编号,如$Proxy0、$Proxy1、$Proxy2之类。经过一些列验证以及代理类名生成后,调用ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags)生成指定代理类的字节码文件。

        private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>{
        //代理类的名字的前缀统一为“$Proxy”
        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) {
                //验证类加载器加载接口得到对象是否与由apply函数参数传入的对象相同
                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");
                }
                //验证这个Class对象是不是接口
                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;     // 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) {
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            //生成指定代理类的字节码文件
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //生成了Proxy的Class对象
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

        (4)ProxyClassFactory的apply方法调用ProxyGenerator.generateProxyClass来生成字节码文件。

  public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        //generateClassFile生成代理类字节码文件
        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;
    }

        生成代理类字节码文件的generateClassFile方法 ,将接口中的方法和Object中的方法添加到代理方法中。

    private byte[] generateClassFile() {
        //下面一系列的addProxyMethod方法是将接口中的方法和Object中的方法添加到代理方法中(proxyMethod)
        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() > '\uffff') {
            throw new IllegalArgumentException("method limit exceeded");
        } else if(this.fields.size() > '\uffff') {
            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);
            }
        }
    }

        (5)字节码生成后,调用defineClass0来解析字节码,生成了Proxy的Class对象。

private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);

  

补充

        1、代理类的存储

        如果所代理的接口都是 public 的,那么它将被定义在顶层包(即包路径为空),如果所代理的接口中有非 public 的接口(因为接口不能被定义为 protect或private,所以除 public之外就是默认的package访问级别,那么它将被定义在该接口所在包,这样设计的目的是为了最大程度的保证动态代理类不会因为包管理的问题而无法被成功定义并访问。

        ProxyGenerator.generateProxyClass函数中 saveGeneratedFiles定义如下,其指代是否保存生成的代理类class文件,默认false不保存,我们可以手动修改。

System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        

         2、代理类的类名

        格式是“$ProxyN”,其中 N 是一个逐一递增的阿拉伯数字,代表 Proxy 类第 N 次生成的动态代理类,值得注意的一点是,并不是每次调用 Proxy 的静态方法创建动态代理类都会使得 N 值增加,原因是如果对同一组接口(包括接口排列的顺序相同)试图重复创建动态代理类,它会很聪明地返回先前已经创建好的代理类的类对象,而不会再尝试去创建一个全新的代理类,这样可以节省不必要的代码重复生成,提高了代理类的创建效率。

        3、类的继承关系

        Proxy 类是它的父类,这个规则适用于所有由 Proxy 创建的动态代理类。而且该类还实现了其所代理的一组接口。

这里写图片描述
        不过这也导致了一个问题,Proxy已经有一个固定的父类叫做Proxy,因此只能对interface进行代理,无法实现对class的动态代理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值