美文网首页
设计模式(二)代理模式

设计模式(二)代理模式

作者: 文泰ChrisTwain | 来源:发表于2023-03-19 23:20 被阅读0次

1.简介

Provide a surrogate or placeholder for another object to control access to it.为一个对象提供一种代理以控制对该对象的访问
---《Design Patterns: Elements of Reusable Object-Oriented Software设计模式-可复用的面向对象软件元素》

代理模式属于结构型设计模式:代理类和真实类实现同一个接口,代理类持有真实类引用,通过代理对象调用真实对象。类图如下所示:


proxy.png
  • 代理模式与现实场景下的代理服务器类似,客户端无法直接访问目标服务器或不便于访问,通过代理服务器中转,达到访问控制目的。类图中客户端针对抽象主题角色进行编程,增加和更换代理类无须修改旧代码,符合开闭原则,达到降低代码解耦或扩展目标对象功能等目的。

  • 代理模式分类
    -- 静态代理:自行编写代理类,即程序运行前就已经存在代理类的字节码文件;
    -- 动态代理:代理类在程序运行期间由JVM根据反射等机制动态的生成,不存在代理类的字节码文件

2.静态代理实现

/**
 * 被代理类接口声明
 */
public interface ISubject {
    void request();
}

/**
 * 定义被代理类
 */
public class SubjectImpl implements ISubject {
    @Override
    public void request() {
        Log.d("SubjectImpl", "被代理类");
    }
}

/**
 * 定义代理类
 */
public class Proxy implements ISubject {

    private ISubject subject;

    public Proxy(ISubject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        subject.request();
    }
}

// 客户端调用
ISubject proxy = new Proxy(new SubjectImpl());
proxy.request();

3.动态代理实现

  • 这里通过JDK InvocationHandler实现动态代理,当然也有其它实现方式
public class DynamicProxy implements InvocationHandler {
    private Object proxyObject;

    // 传入被代理类作为参数,生成代理对象。将代理对象与此InvocationHandler关联,代理对象调用代理方法时将调用InvocationHandler#invoke()
    public <T> T newProxyInstance(Object proxyObject) {
        this.proxyObject = proxyObject;
        return (T) Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(),
                proxyObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = method.invoke(proxyObject, args);
        // doing somthing else.
        return result;
    }
}

// 客户端调用,复用前面静态代理中定义的接口和被代理类
DynamicProxy dynamicProxy = new DynamicProxy();
ISubject proxy = dynamicProxy.newProxyInstance(new SubjectImpl());
proxy.request();
  • Proxy#newProxyInstance()参数说明
    ClassLoader loader:指定产生代理对象的类加载器,与传入的proxyObject相同的类加载器
    Class<?>[] interfaces:指定目标对象的实现接口,即要给目标对象提供一组调用接口
    InvocationHandler h:指定关联的InvocationHandler对象,当代理对象proxy调用方法时能关联到invoke()方法

  • 注意
    newProxyInstance()方法返回值和invoke(Object proxy, ...)方法的第一个参数是真正生成的代理对象。
    自动生成的代理对象实现了ISubject接口,通过proxy.request()调用时,方法的内部实现将调用InvocationHandler#invoke()方法并传递通过反射获取的方法名、参数等,最终在InvocationHandler#invoke()方法中执行自己的逻辑。

  • 动态代理与静态代理相比有如下优点:不用对每个被代理类都手动写一个代理类,所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke),在接口方法数量比较多的时候,可以更灵活处理。

  • 通过JDK提供的动态代理方式可以直接创建一个接口的实例,实际业务中可利用此方式做一些特殊操作,如Retrofit网络请求接口的实现(笔者不认为Retrofit使用了代理模式,只是使用了InvocationHandler的特性构造网络请求参数):

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(        // 通过JDK动态代理的方式生成网络请求接口的实例类
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                Platform platform = Platform.get();
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);    // 解析请求接口的注解和方法参数构造请求参数,生成OkHttp call
              }
            });
  }
  • 通过动态代理方式也能实现如下调用:类似接口回调,调用系统接口时传入动态代理类,底层可反过来通过此代理类控制上层逻辑调用
private void init(Context context) {
    try {
        Class<?> cls = Class.forName("com.me.test.MyManager");  // Framework层提供管理类和接口
        Class callbackCls = Class.forName("com.me.test.MyManager$IMyCallback");
        Constructor constructorMyManager = cls.getConstructor(new Class[] {Context.class, callbackCls});

        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Object objectCallback = Proxy.newProxyInstance(HostAbility.class.getClassLoader(),
                new Class[] {callbackCls}, myInvocationHandler);  // APK中完成接口实例化

        Object myManager = constructorMyManager.newInstance(new Object[] {context, objectCallback});  // 将生成的接口传给系统层
        RealManager realManager = (RealManager) myManager;  // apk可调用系统提供的管理类达到一定控制,系统被调用后也可控制触发apk相关逻辑在InvocationHandler中
    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException
            | InvocationTargetException | InstantiationException e) {
        Logger.e(TAG, "exception in reflecting callback");
    }
}

private class MyInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // checking
        if (args == null || args.length < LENGTH) {
            Logger.e(TAG, "unexpected callback!");
            return null;
        }

        // 获取参数
        long p1 = ((Long) args[0]);
        int p2 = ((Integer) args[1]);
        int p3 = ((Integer) args[2]);

        // doing something 由系统在Framework层调用接口后回调到APK中执行,达到由系统层控制上层业务
        return null;
    }
}
参考

refactoringguru-代理模式
从Retrofit看懂动态代理模式
一定能看懂的 Retrofit 最详细的源码解析
深入理解Retrofit动态代理
枚举、动态代理的原理

相关文章

  • 前端设计模式

    JS设计模式一:工厂模式jS设计模式二:单例模式JS设计模式三:模块模式JS设计模式四:代理模式JS设计模式五:职...

  • Mybatis代理设计模式(Proxy)与编程实现原理

    最易懂设计模式解析适配器设计模式模板方法设计模式Mybatis多级代理 1. 认识代理模式 1.1 模式定义 给某...

  • 模板方法设计模式(Template Method)

    最易懂设计模式解析适配器设计模式Mybatis代理设计模式Mybatis多级代理 1. 认识模板方法模式 1.1 ...

  • 适配器设计模式(Adapter)

    最易懂设计模式解析模板方法设计模式Mybatis代理设计模式Mybatis多级代理 1. 认识适配器模式 1.1 ...

  • 理解java的代理模式和动态代理

    代理模式 代理模式是23种设计模式之一,属于结构型模式。代理模式是最常见也是最常用的模式之一,只不过有很多设计模式...

  • spring框架中的设计模式二

    在这篇文章中,介绍4种设计模式。结构型设计模式:代理和复合模式。行为型设计模式:策略和模板方法模式。 代理模式 面...

  • 10、结构型模式-代理设计模式

    1、加盟商来啦-你需要掌握的代理设计模式 简介:讲解代理设计模式,让代理帮你完成工作 代理设计模式(Proxy P...

  • 设计模式之代理模式

    设计模式之代理模式 10分钟看懂动态代理设计模式(升级篇)-对这篇动态代理模式的思路整理 仿JDK实现动态代理逻辑...

  • 动态代理原理解析

    注:源自于Android 一、代理模式 代理模式是java23种设计模式常用的一种设计模式。代理模式是客户端不直接...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

网友评论

      本文标题:设计模式(二)代理模式

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