Skip to content

代理模式

动态代理

  • 想将额外的操作从实际对象分离,可以通过代理去调用对象,通过是否使用代理对对象进行操作,决定是否要进行一些额外操作
  • 动态代理允许在运行时创建一个符合某些给定接口的代理对象,此对象可以在调用实际方法前后执行特定操作。
    interface Interface {
      void doSomething();
      void somethingElse(String arg);
    }
    
    class RealObject implements Interface {
      @Override public void doSomething() {
        System.out.println("doSomething");
      }
      @Override public void somethingElse(String arg) {
        System.out.println("somethingElse " + arg);
      }
    }
    
    class DynamicProxyHandler implements InvocationHandler {
      private Object proxied;
      DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
      }
        //任何通过代理对象发起的方法调用都会被转发到这个接口的 invoke 方法。
      @Override public Object
      invoke(Object proxy, Method method, Object [] args)
      throws Throwable {
        System.out.println(
          "**** proxy: " + proxy.getClass() +
          ", method: " + method + ", args: " + args);
        if(args != null)
          for(Object arg : args)
            System.out.println("  " + arg);
        return method.invoke(proxied, args);
      }
    }
    
    class SimpleDynamicProxy {
      public static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
      }
      public static void main(String [] args) {
        RealObject real = new RealObject();
        consumer(real);
        // 创建动态代理(在运行时动态创建一个实现了指定接口的代理对象)
        Interface proxy = (Interface)Proxy.newProxyInstance(
          Interface.class.getClassLoader(),
          new Class []{ Interface.class },//会被代理的接口(方法),可以有多个
          new DynamicProxyHandler(real));
          //得到了一个代理对象
        consumer(proxy);
      }
    }
    
  • Proxy.newProxyInstance 需要三个参数:类加载器、一组接口以及一个 InvocationHandler 实例。
import java.lang.reflect.*;
// Step 1: Define interfaces
interface Interface1 {
    void doSomething();
}
interface Interface2 {
    void doSomethingElse();
}
// Step 2: Create implementations
class Implementation1 implements Interface1 {
    public void doSomething() {
        System.out.println("Implementation1 doing something");
    }
}
class Implementation2 implements Interface2 {
    public void doSomethingElse() {
        System.out.println("Implementation2 doing something else");
    }
}
// Step 3: Create dynamic proxy
class MixinProxy implements InvocationHandler {
    private final Object [] delegates;

    public MixinProxy(Object... delegates) {
        this.delegates = delegates;
    }

    public Object invoke(Object proxy, Method method, Object [] args) throws Throwable {
        for (Object delegate : delegates) {
            if (method.isInstance(delegate)) {
                return method.invoke(delegate, args);
            }
        }
        throw new UnsupportedOperationException("Method not supported: " + method);
    }
    //帮助创建动态代理
    @SuppressWarnings("unchecked")
    public static <T> T createMixinProxy(Class <T> interfaceClass, Object... delegates) {
        //取出传入对象的类型
        Class <?> [] interfaces = new Class <?> [delegates.length];
        //存储接口
        for (int i = 0; i < delegates.length; i++) {
            interfaces [i] = delegates [i].getClass().getInterfaces()[0];
        }
        return (T) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(),
                interfaces,
                new MixinProxy(delegates)
        );
    }
}
// Using the mixin
public class MixinDemo {
    public static void main(String [] args) {
        Object mixin = MixinProxy.createMixinProxy(Object.class, new Implementation1(), new Implementation2());
        //还需要手动转换类型
        Interface1 if1 = (Interface1) mixin;
        Interface2 if2 = (Interface2) mixin;
        if1.doSomething();
        if2.doSomethingElse();
    }
}

标签接口

  • 标签接口是没有定义任何方法的接口。标签接口的主要作用是为实现该接口的类提供一个特定的标识。这个标识允许类在运行时表现出一些特殊的行为。
    class NullRobotProxyHandler
    implements InvocationHandler {
      private String nullName;
      private Robot proxied = new NRobot();
      NullRobotProxyHandler(Class <? extends Robot> type) {
          //区分不同 Robot 子类的 Null 对象
        nullName = type.getSimpleName() + " NullRobot";
      }
        //NULL 就是一个标签接口
      private class NRobot implements Null, Robot {
        @Override
        public String name() { return nullName; }
        @Override
        public String model() { return nullName; }
        @Override public List <Operation> operations() {
          return Collections.emptyList();
        }
      }
        //传递操作
      @Override public Object
      invoke(Object proxy, Method method, Object [] args)
      throws Throwable {
        return method.invoke(proxied, args);
      }
    }
    
    public class NullRobot {
        //通过代理创建具有空标签的对象
      public static Robot
      newNullRobot(Class <? extends Robot> type) {
        return (Robot)Proxy.newProxyInstance(
          NullRobot.class.getClassLoader(),
          new Class []{ Null.class, Robot.class },
          new NullRobotProxyHandler(type));
      }
      public static void main(String [] args) {
        Stream.of(
          new SnowRobot("SnowBee"),
          newNullRobot(SnowRobot.class)
        ).forEach(Robot:: test);
      }
    }
    
  • 使用代理的提供一种通用的方式来创建任何类型的Robot的空对象,而不需要为每个Robot子类都创建一个特定的空对象类。
  • 通过使用代理,你可以为任何Robot子类创建一个空对象,而不需要写任何额外的代码。这是因为代理对象的所有方法调用都会被转发给NullRobotProxyHandler对象,然后由这个对象的invoke方法处理。这个方法将方法调用转发给NRobot对象,这个对象的所有方法都返回一个无操作的结果。