设计模式——代理(Proxy)

代理模式是一种结构型模式。代理模式给某一对象提供一个代理对象,并且由代理对象控制对原对象的引用。

#代理模式的结构

所谓代理就是由一个代理对象去代替处理目标对象,而处理的逻辑是由代理对象引用并调用目标对象进行处理的,也就是最终仍然是目标对象处理相应的逻辑,代理对象仅仅起到了中介作用。

代理模式结构图:

这里写图片描述

在代理模式中的角色:

  • 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。(利用接口,公开申明了需求特性,目标对象和代理对象均实现了这一接口,满足这一需求特性,那么客户端认为他们均满足条件,均可使用,亦可替代)
  • 目标对象角色:定义了代理对象所代表的目标对象。(核心代码对象)
  • 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。

#使用场景:

在实际开发过程中,代理类的实现比上述代码要复杂很多,代理模式根据其目的和实现方式不同可分为很多种类,其中常用的几种代理模式简要说明如下:

  • (1) 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。
  • (2) 虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
  • (3) 保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
  • (4) 缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  • (5) 智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等。
    在这些常用的代理模式中,有些代理类的设计非常复杂,例如远程代理类,它封装了底层网络通信和对远程对象的调用,其实现较为复杂。

#静态代理

所谓静态代理就是手动编写代理类。在大规模代理很多对象的时候并不方便。

代码实现传送门

#动态代理

相对应的,动态代理就是自动生成代理类。

这点非常神奇,因为是在我们运行的时候,动态生成了一个类,并且该类又编译加载进编译器,可以生成该类的对象使用了,达到这点说明Java是动态语言了。

使用场景:

  • 日志
  • 权限控制
  • Transition
  • 方法前后做一些特殊固定操作
  • ….

#Java 动态代理类Proxy

Proxy中生成接口的实现类代码(native层实现):

private static native Class<?> generateProxy(String name, Class<?>[] interfaces,ClassLoader loader, Method[] methods,Class<?>[][] exceptions);

Proxy中利用反射创建对象:

return getProxyClass(loader, interfaces).getConstructor(InvocationHandler.class).newInstance(invocationHandler);

Retrifit2中的动态代理使用:

return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, 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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });

缺点:Java的动态代理类Proxy必须要让目标类实现接口,如果没有实现相应接口就无法使用Proxy创建出目标类的代理类对象。这时候就需要借助CGLib创建动态代理类了。

#CGLib(字节码技术)

CGLib可以不需要目标类实现相应接口,一个普通类就可以给其动态生成代理类了。

CGLib动态代理原理及实现

猜你喜欢

转载自blog.csdn.net/yuanyang5917/article/details/52413193