jdk实现动态代理

介绍

代理是一种设计模式,提供了对目标对象另外的访问方式,通过代理对象来访问目标对象,这样可以扩展目标对象的功能,对目标对象功能做控制。
类图如下

静态代理

定义一个目标对象和代理对象都需要实现的接口

/**
 * 可以唱歌的
 */
public interface Singable {
  /**
   * 唱歌
   */
  void sing();
}

目标对象

/**
 * 歌手
 */
public class Singer implements Singable {
  @Override
  public void sing() {
    System.out.println("I am singing...");
  }
}

代理对象

/**
 * 歌手经纪人
 */
public class SingerAgent implements Singable {

  private Singable delegate;

  public SingerAgent(Singable delegate) {
    this.delegate = delegate;
  }

  @Override
  public void sing() {
    System.out.println("before sing...");
    delegate.sing();
    System.out.println("after sing...");
  }
}

客户端调用

public class Client {
  public static void main(String[] args) {
    Singer singer = new Singer();
    SingerAgent singerAgent = new SingerAgent(singer);
    singerAgent.sing();
  }
}

输出结果

before sing...
I am singing...
after sing...

这个例子就相当于我们想找周杰伦唱歌,必须先找周杰伦经纪人,经纪人负责费用等唱歌前以及唱歌后的工作,周杰伦就负责唱歌。
静态代理的缺点:
代理和目标对象必须实现相同的接口,接口有变化,目标对象和代理都要维护。为了解决这个缺点,我们可以使用动态代理。

动态代理

动态代理其实是可以不实现接口的,但jdk动态代理必须实现,后续的如cglib实现动态代理就不需要了。今天的例子为jdk动态代理。

/**
 * 可以唱歌的
 */
public interface Singable {
  /**
   * 唱歌
   */
  void sing();
}
/**
 * 歌手
 */
public class Singer implements Singable {
  @Override
  public void sing() {
    System.out.println("I am singing...");
  }
}

动态代理处理

public class SingerInvocationHandler implements InvocationHandler {

  private Object delegate;

  public SingerInvocationHandler(Object delegate) {
    this.delegate = delegate;
  }


  /**
   * 动态代理调用方法
   *
   * @param proxy  生成的代理对象
   * @param method 代理的方法
   * @param args   方法参数
   * @return
   * @throws Throwable
   */
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("before sing ");
// 目标对象方法调用
    Object ret = method.invoke(delegate, args);
    System.out.println("after sing ");
    return ret;
  }

  /**
   * 创建代理对象
   * @return
   */
  public Singable newProxyInstance() {
    return (Singable) Proxy.newProxyInstance(
        delegate.getClass().getClassLoader(),
        delegate.getClass().getInterfaces(),
        this);
  }
}

InvocationHandler 顾名思义为调用处理器,每一个代理对象实例都会有一个调用处理器对象。创建代理对象主要使用的时Proxy的newProxyInstance方法,
方法参数依次为

  1. 加载代理类的类加载器
  2. 代理类需要实现的接口
  3. 调用处理器
public class Client {
  public static void main(String[] args) {
   //保存创建的代理类
System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", Boolean.TRUE.toString());
    Singer singer = new Singer();
    SingerInvocationHandler singerInvocationHandler = new SingerInvocationHandler(singer);
    Singable proxy = singerInvocationHandler.newProxyInstance();
    proxy.sing();
  }
}

输出结果为

before sing 
I am singing...
after sing 

生成的代理类为

public final class $Proxy0 extends Proxy implements Singable {
  private static Method m1;
  private static Method m2;
  private static Method m3;
  private static Method m0;

  public $Proxy0(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 sing() 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.imooc.sourcecode.java.dynamicproxy.jdk.test2.Singable").getMethod("sing");
      m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    } catch (NoSuchMethodException var2) {
      throw new NoSuchMethodError(var2.getMessage());
    } catch (ClassNotFoundException var3) {
      throw new NoClassDefFoundError(var3.getMessage());
    }
  }
}

jdk帮我们创建了4个方法,equals,toString,hashCode3个方法都是Object类的,sing方法是目标接口的。

总结

代理模式的本质就是控制对象访问。

posted @ 2020-08-04 23:40  strongmore  阅读(460)  评论(0编辑  收藏  举报