java 动态代理学习笔记
java 动态代理学习笔记
漂泊的二货 发表于7个月前
java 动态代理学习笔记
  • 发表于 7个月前
  • 阅读 3
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

代理模式:代理模式就是对一个对象进行包装,包装生成的对象具有和原对象一样的方法列表,但是每个方法都进行了包装

 

静态代理

public interface MoveAble {
    
    public void run();
}

public class Car implements MoveAble {

    @Override
    public void run() {
        System.out.println("car is running");
    }

}

public class CarProxy implements MoveAble{
    
    private MoveAble target;

    public CarProxy(MoveAble target) {
        super();
        this.target = target;
    }

    @Override
    public void run() {
        this.target.run();
    }
    
    public static void main(String[] args) {
        CarProxy proxy = new CarProxy(new Car());
        proxy.run();
    }
    
}

    首先 我们定义了一个MoveAble接口,然后新建一个实现类,并且新建一个CarProxy代理类,CarProxy实现moveAble接口,同时在它内部定义一个变量MoveAble用来保存代理的实现类,这样代理类实现moveAble接口中的run方法时,其实调用的还是被代理类car中的run方法,同时 我们可以在代理类CarProxy中的run方法中添加 我们需要添加的逻辑,这样就完成了对car的代理。但是如果moveAble中添加方法时,代理类CarProxy也要增加相应的实现;如果不想这样的话,就得使用动态代理;

动态代理

下面我们征对上面的静态代理类 我们创建一个动态的代理类:

public class MoveAbleProxy implements InvocationHandler{
    
    private Object target;


    public MoveAbleProxy(Object target) {
        super();
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println(proxy.getClass().getSimpleName());
        method.invoke(target, args);
        return null;
    }
    
    public static void main(String[] args) {
        MoveAble car = new Car();
        //得到的moveProxy实现了MoveAble接口 继承了Proxy
    MoveAble moveProxy = (MoveAble)Proxy.newProxyInstance(car.getClass().getClassLoader(),         car.getClass().getInterfaces(), new MoveAbleProxy(car) ); 
        moveProxy.run();     
    }

}

这边与静态代理的区别在于 动态代理类实现的是InvocationHandler,与静态代理的main方法中测试代码比较会发现静态代理中我们是直接new CarProxy ,而在动态代理中我们是:

Proxy.newProxyInstance(car.getClass().getClassLoader(),         car.getClass().getInterfaces(), new MoveAbleProxy(car) ); 并将返回的对象强转成MoveAble。

所以动态代理的实现要一下几步:

(1)要定义一个接口,和一个该接口的实现类,这个实现类就是我们要代理的对象,代理其实就是在调用实现类方法时,在该方法的调用前后增加一个逻辑

(2)动态的代理类中必须要实现InvocationHandler接口,实现invoke方法。动态代理中生成的代理实例不会去直接调用实现类的方法,而是调用invoke方法。

(3)生成的代理里去调用实现类的方法时

MoveAble moveProxy = (MoveAble)Proxy.newProxyInstance(car.getClass().getClassLoader(),         car.getClass().getInterfaces(), new MoveAbleProxy(car) ); 

断点会发现moveProxy = $Proxy0 ,可以在main测试方法中添加

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");可以看一下该生成的代理类的源码:(moveProxy 其实是 实现了MoveAble接口 继承了Proxy)

public final class $Proxy0
  extends Proxy
  implements MoveAble
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void run()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.myec.com.MoveAble").getMethod("run", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

在Proxy中的newProxyInstance的方法中:

   

 Class cl = getProxyClass(loader, interfaces);
    try {
        Constructor cons = cl.getConstructor(constructorParams);
        return (Object) cons.newInstance(new Object[] { h });
    } 

1这个生成了代理类的字节码,然后用参数里的classLoader加载这个代理类,生成$Proxy0实例

2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler(MoveAbleProxy )的子类传入。

3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的car.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成MoveAble类型来调用接口中定义的方法。

 

 

 

 

 

 

共有 人打赏支持
粉丝 0
博文 1
码字总数 1138
×
漂泊的二货
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: