美文网首页Java高级
Java高级--动态代理

Java高级--动态代理

作者: 初夏的雪 | 来源:发表于2020-12-08 00:28 被阅读0次

    什么是代理模式?

    代理模式就是为其他对象提供一种代理来对该对象进行访问控制。

    ​ 生活实例:

    ​ 1)房产中介,他就是一个代理,由房东全权授权中介来进行房产的售前咨询,相关事宜的处理等。

    ​ 2)滴滴代驾,就是授权代驾可以驾驶你的车辆,并将车辆行驶至目的地,期间代驾可以进行对车辆的一些简单的操作。

    代理---“铁三角”:

    1. 抽象角色:

      为“代理角色”和“真实角色”提供的一套对外的公共方法(一般定义为接口)
    interface ProxyInterface {
        fun confirmAction(inputString :String,name:String);
    }
    
    1. 真实角色:

      ​ 真正的业务实现逻辑,他需要实现“抽象角色”中的接口;

    class RealInstance : ProxyInterface {
    
        private val TAG  = "RealInstance";
        override fun confirmAction(inputString: String,name: String) {
            Log.e(TAG,"真实实例对象----"+"调用confirmAction()")
        }
    }
    
    1. 代理角色:

      ​ 他同“真实角色”一样,实现了“抽象角色”中的接口,同时拥有对“真实角色”的引用,然后通过“真实角色”的引用来实现“抽象角色”中的抽象方法,且可以自己在抽象方法中增加自己的一些操作等。

    class ProxyInstance(realInstance: RealInstance) : ProxyInterface {
        val TAG = "ProxyInstance";
    
        var mRealInstance: RealInstance = realInstance
        override fun confirmAction(inputString: String,name:String) {
            Log.e(TAG, "我是代理,我的confirmAction被调用")
            mRealInstance.confirmAction(inputString,name)
        }
    }
    

    ​ 三者之间的类关系如图所示:


    铁三角类图.png

    了解了上面的“铁三角”,那相信我们对代理模式就已经完全明白了代理模式了。。。。很简单吧!!!!别高兴的太早了,一步一步带你进去深渊。。。。

    代理的用途:

    1. 通过引入代理对象的方式来间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性;
    2. 通过代理对象进行对访问的控制;

    好,那我们就来聊聊怎么使用? 今天先聊一下静态代理和动态代理。

    代理使用:

    1)静态代理:

    ​ 顾名思义,就是我们在实现代理模式时,在编辑阶段就需要将对象的代理者都准备好,在程序运行时使用。

    val proxyInstance = ProxyInstance(RealInstance())
    proxyInstance.confirmAction("测试代理模式","")
    

    缺点:

    1.当需要代理的真实角色多时,我们的代理对象是不是也需要很多,这样就会出现代理对象和代码量变大的情况

    2.如果我们想要扩展一下抽象接口的方法,那么真实角色和代理角色都需要维护,这样是不是维护、扩展能力也比较差

    ​ 既然静态代理有那么明显的缺点,我们有没有办法解决呢,答案是肯定的,这就是我们下面的动态代理。

    2)动态代理:

    ​ 相对于静态代理而言,动态代理则是在程序运行时再创建对象的代理类和实例,也就是说有程序帮我们去创建代理类及其实例,这样效率很明显要低些。

    JDK已经为我们提供好了API了,我们直接用JDK API就可以了,如下:

     val newProxyInstance = Proxy.newProxyInstance(RealInstance::class.java.classLoader,
                    arrayOf(ProxyInterface::class.java),
                    object : InvocationHandler {
                        override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
                            if (args?.size!! > 1) {
                                return method?.invoke(RealInstance(), args[0],args[1])
                            }
                            return null
                        }
                    }
                ) as ProxyInterface
    
    newProxyInstance.confirmAction("hello","我是代理对象");   
    

    上述代码中,有两个关键的API: Proxy和InvocationHandler,下面我们就深入“敌营”来了解一下。

    源码剖析:

    Proxy 提供了创建动态代理类和实例的静态方法,它也是有这些方法穿件的所有动态代理类的超类。是一个实现在运行时进行创建直接接口列表的类。

    先来看看动态代理实现的流程图,


    动态代理原理流程图.jpg

    然后再看源码,下面源码已经做了详细的备注。

    Proxy 类中的成员变量和方法:

    package java.lang.reflect;//在此包下
    
    /////////////////////////////////////////////////////////////////////////////////
    
    //静态成员
    
      private static final Class<?>[] constructorParams =
            { InvocationHandler.class };
    
    
    /**
    * 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。 
    *----loader - 类加载器来定义代理类---当前真实角色的类加载器
    *----interfaces - 代理类实现的接口列表   他是一个数组:因为一个代理可以代理多个实例对象
    *----h - 调度方法调用的调用处理函数 
    */
      @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            //复制一份抽象接口类,并保存到数组中
            final Class<?>[] intfs = interfaces.clone();
    
            /*
             * Look up or generate the designated proxy class.
             * 查找或生成代理类
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                //获取代理类的public构造方法的引用
                final Constructor<?> cons = cl.getConstructor(constructorParams);//constructorParams 静态成员
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    cons.setAccessible(true);
                }
                
                //使用带指定参数:h的构造器cons来生成该构造器所代表的代理类的实例,并将该代理类实例返回
                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);
            }
        }
    
    
    ///////////////////////////////////////////////////////////
      /**
         * a cache of proxy classes
         代理类的缓存
         */
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new 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);
        }
    

    代理的缓存WeakCache

    package java.lang.reflect;
    
    
     public V get(K key, P parameter) {
            Objects.requireNonNull(parameter);
    
            expungeStaleEntries();
    
            //使用外部传入的key 生成cacheKey
            Object cacheKey = CacheKey.valueOf(key, refQueue);
    
            // lazily install the 2nd level valuesMap for the particular cacheKey
         //线程安全的原子操作担保 ConcurrentMap
            ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
            if (valuesMap == null) {
                //从原缓存map中查找cacheKey ,如果找不到则创建一个新的map 添加到缓存map中,并将新的map一起返回
                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
             //1.使用可以生成subkey ,从新的map获取可以对应的Supplier提供者
            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
                    //如果supplier不为空,则直接取出supplier中的值返回
                    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);
                    }
                }
            }
        }
    

    Invocationhandler接口类

    //每一个代理类实例有一个相对应的InvocationHandler句柄,一旦代理类实例调用了其中一个method方法都会触发该句柄的invoke方法,并将相关信息返回
    //1 proxy 代理类实例
    //2 method ,调用的方法,
    //3 args   该用法的参数
    public interface InvocationHandler {
        
     public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    

    ProxyClassFactory 最终类通过反射来生成代理类

      @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    /*
                     * Verify that the class loader resolves the name of this
                     * interface to the same Class object.
                     */
                    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");
                    }
                    /*
                     * Verify that the Class object actually represents an
                     * interface.
                     */
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
                    /*
                     * Verify that this interface is not a duplicate.
                     */
                    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;
    
                /*
                 * 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 the default package.
                    proxyPkg = "";
                }
    
                {
                    // Android-changed: Generate the proxy directly instead of calling
                    // through to ProxyGenerator.
                    List<Method> methods = getMethods(interfaces);
                    Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                    validateReturnTypes(methods);
                    List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
    
                    Method[] methodsArray = methods.toArray(new Method[methods.size()]);
                    Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
    
                    /*
                     * Choose a name for the proxy class to generate.
                     */
                    long num = nextUniqueNumber.getAndIncrement();
                    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                    return generateProxy(proxyName, interfaces, loader, methodsArray,
                                         exceptionsArray);
                }
            }
        }
    

    说了半天的动态代理,那么动态代理到底生成的类长啥样呢,我们如何才可以看到呢?

    查询动态代理类

    1. 新建一个java module
    2. 将上述抽象接口和真实角色的class 考入java module中
    3. 新建一个ProxyUtils类
     public static void generateClassFile(Class clazz,String proxyName)
        {
            byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
            String path = clazz.getResource(".").getPath();
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(path + proxyName + ".class");
                fos.write(classFile);
                fos.flush();
            }catch(Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    fos.close();
                }catch(IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            Subject subject=new Subject();//此处为真实角色的对象
            ProxyInterface proxy =(ProxyInterface) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
                    new Class[]{ProxyInterface.class},
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                            return null;
                        }
                    });
            generateClassFile(Subject.class,"SubjectProxy");//第二个参数是生成的代理类名
            proxy.confirmAction();
        }
    
    1. 运行ProxyUtils类的Main函数,则会在build/classes/java/main/com/XXX/proxylib/目录下生成 SubjecProxy.class文件
    2. 分析一下这个class文件

      1.他是一个最终类,并且继承Proxy ,实现了我们自己的抽象接口ProxyInterface
      2.有一个public 修饰的构造函数,并且InvocationHandler作为参数
      3.重写了Object的equals()、toString()、hasCode()方法
      4.实现了抽象接口ProxyInterface的方法,方法体是使用InvocationHandler实例来调用它的invoke方法,并将代理实例、方法、参数作为参数回调回去
      5.静态代码区:通过反射实现类名和方法的反射,并将反射的method存放到静态变量中

    实际运行生成的代码如下:

    public final class SubjectProxy extends Proxy implements ProxyInterface {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public SubjectProxy(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 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 confirmAction() 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);
            } 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"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.leon.proxylib.ProxyInterface").getMethod("confirmAction");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    

    到此为止,已经将java的动态代理,代理模式包括相关源码的剖析都已经介绍完了,有需要的同学的可以自己跟着上面的额内容实操一下加强记忆。

    知识点总结:

    1、设计模式---代理模式

    2、调用处理器InvocationHandler

    3、Java反射机制

    4、Map缓存机制

    今天就学习到这里了,欢迎来踩点

    相关文章

      网友评论

        本文标题:Java高级--动态代理

        本文链接:https://www.haomeiwen.com/subject/iznxgktx.html