美文网首页
代理设计模式

代理设计模式

作者: gczxbb | 来源:发表于2019-03-15 17:44 被阅读0次

    一、静态代理

    代理设计模式,代理类和真实类有相同接口,代理类对外隐藏真实类,使用者只关系使用的接口功能,不清楚使用的是代理类还是真实类,满足功能即可。
    静态代理,编译时,将接口,代理类,真实类定义好,class文件生成,按照Jvm正常的加载流程运行。
    举例,接口。

    public interface Base {
        String hi();
    }
    

    代理类

    public class ProxyBase implements Base{
        RealBase real ;
        public ProxyBase(RealBase real) {
            super();
            this.real = real;
        }
    
        @Override
        public String hi() {
            return real.hi();
        }
    }
    

    真实类

    public class RealBase implements Base {
        @Override
        public String hi() {
            return "Real";
        }   
    }
    

    真实类和代理类都实现Base接口,代理类引用真实类对象,代理类方法调用真实类方法。

    二、动态代理

    动态代理,运行时,根据接口动态生成一个新代理类,优点是可以对所有的代理类实现的接口方法统一处理,路由到一个地方,InvocationHandler的invoke方法,通过Method识别调用的代理方法,触发真实类target的对应方法,也可以对所有方法统一加内容,比如统计打点时间。
    举例,Retrofit类,利用动态代理生成interface的代理对象。

    public <T> T create(final Class<T> service) {
        ...
        return (T) Proxy.newProxyInstance(service.getClassLoader(), 
            new Class<?>[] { service },  new InvocationHandler() {
                //该对象传入$Proxy0的构造方法中
                private final Platform platform = Platform.get();
                @Override 
                public Object invoke(Object proxy, Method method, Object... args) 
                            throws Throwable {
                    ...
                  }
            });
    }
    

    Retrofit类的create方法,调用Proxy类的newProxyInstance方法,参数是类加载器ClassLoader,interface数组,InvocationHandler。

    public static Object newProxyInstance(ClassLoader loader, 
                    Class<?>[] interfaces,
                    InvocationHandler invocationHandler)
                    throws IllegalArgumentException {
        Exception cause;
        try {
            return getProxyClass(loader, interfaces)
                    .getConstructor(InvocationHandler.class)
                    .newInstance(invocationHandler);
        } catch (NoSuchMethodException e) {
        }
    }
    

    Class<?>[]数组只有一个interface元素,Xxx.class服务类型。

    public static Class<?> getProxyClass(ClassLoader loader, 
                        Class<?>... interfaces)
                        throws IllegalArgumentException {
        final List<Class<?>> interfaceList = 
                        new ArrayList<Class<?>>(interfaces.length);
        ...
        synchronized (loader.proxyCache) {
            //缓存中查找
            Class<?> proxy = loader.proxyCache.get(interfaceList);
            if (proxy != null) {
                return proxy;
            }
        }
        ...
        List<Method> methods = getMethods(interfaces);
        Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
        ...
        String baseName = commonPackageName != null && !commonPackageName.isEmpty()
                    ? commonPackageName + ".$Proxy"
                    : "$Proxy";
        Class<?> result;
        synchronized (loader.proxyCache) {
            result = loader.proxyCache.get(interfaceList);
            if (result == null) {
                //Proxy每生成一个$Proxy,nextClassNameIndex(静态)自动+1
                String name = baseName + nextClassNameIndex++;
                result = generateProxy(name, interfaces, loader, methodsArray, exceptionsArray);
                loader.proxyCache.put(interfaceList, result);
            }
        }
        return result
    }
    

    保存一份Map缓存,List<Class<?>>是key,value是interface服务的代理类Class<?> proxy。
    遍历Class<?>数组,获取List<Method>,排序,增加equal,toString,hashCode三个基类方法。
    根据name,Class<?>数组和List<Method>,native方法,即generateProxy方法,创建一个新类,命名为Xxx$Proxy数字,新类继承Proxy类,实现interface的方法。
    generateProxy方法,创建Class<?>类型。
    Map缓存防止每次对相同interface服务创建动态代理时都生成一次新类,反射影响性能。
    getConstructor方法,获取新类带InvocationHandler参数的构造方法,创建新类实例对象。

    protected Proxy(InvocationHandler h) {
        this.h = h;
    }
    

    将新类的对象返回,对Proxy0类反编译,该类中所有的interface方法会触发super.h.invoke方法。父类的h是创建新类对象时传入的InvocationHandler对象。因此,每一个interface方法调用,被InvocationHandler的invoke方法拦截。

    三、总结

    动态代理这一套固定代码可以无侵入扩展各种服务interface的api。核心逻辑是创建一个实现interface接口方法的Proxy代理子类,实现的interface方法均由我们上层强行插入的InvocationHandler统一路由处理。

    利用Proxy#方法,根据虚拟机运行时动态生成新类,创建一个对象,命名方式以$开头,Proxy+数字,继承Proxy。

    新创建类和interface的关系加入Map缓存,防止每次创建同一个服务的动态代理类时都生成一次新类,影响性能。


    任重而道远

    相关文章

      网友评论

          本文标题:代理设计模式

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