动态代理

java动态代理的前提条件是,代理对象必须实现了某个接口。如果没有实现接口,就需要用cglib代理。

构造代理类需要三个信息:

  • 目标类的类加载器 
  • 目标类实现的接口
  • 代理处理句柄

生成的代理类 继承Proxy 并且 实现目标类的接口

然后调用Proxy构造方法,设置处理句柄 InvokeHandler h

假设目标类: TargetImp

目标类接口: Target

自定义处理句柄: MyInvoke implements InvocationHandler

那么代理类 $taget0 大概就是这样的结构:

$taget0 extends Proxy implements Target {

  Medhod m1;

  Medhod m2;

  ...

  Medhod m1;

 //.....

}

InvocationHandler 设置时通过调用Proxy的newProxyInstance(Object ,Method , Object[] ) 

然后该方法内部调用Proxy的构造方法,Proxy(InvocationHandler h)设置处理句柄.

其实所有的代理处理逻辑都在InvocationHandler  的 invoke方法中。

 

$taget0 执行方法其实就是调用invoke(this,m1,args)类似这样

$taget0内部会对应每一个方法生成一个方法的句柄 Method m1 ...

然后执行时会调用父类InvocationHandler属性的invoke方法

super.h.invoke(this,m1,args);

 

实例:

接口 Target.java

package proxy.dynamic;

public interface Target {
    public void say();
    public void play();
}

目标类 TargetImp.java

package proxy.dynamic;

public class TargetImp implements Target{
    public void say(){
        System.out.println("Target say()");
    }

    public void play(){
        System.out.println("Target play()");
    }
}

处理逻辑 MyInvoke.java

package proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvoke implements InvocationHandler{
    Object target;
    public MyInvoke(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName() == "say") {
            System.out.println("begain say()");
        }
        if (method.getName() == "play") {
            System.out.println("begain play()");
        }
        Object res = method.invoke(target, args);
        if (method.getName() == "say") {
            System.out.println("end say()");
        }
        if (method.getName() == "play") {
            System.out.println("end play()");
        }
        return res;
    }
}

测试类 DynamicProxy.java

package proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxy {
    public static void main(String[] args) {
        final Target target = new TargetImp();
        InvocationHandler myInvoke = new MyInvoke(target);
        Target targetProxy = (Target) Proxy.newProxyInstance(TargetImp.class.getClassLoader(),TargetImp.class.getInterfaces(),myInvoke);

        targetProxy.say();
        targetProxy.play();

    }
}

执行结果:

begain say()
Target say()
end say()
begain play()
Target play()
end play()

 

然后我们进一步看看代理生成的类在哪,在虚拟机中是什么样的结构

这里用jdk提供的虚拟机调试工具 hsdb 调试

先来看一下生成的类:

 

我们看到生成了一个代理类$Proxy0, 下面看一下类的结构

 

 这里显示了:

  • $Proxy0 的父类
  • 实现的接口
  • 一些方法的句柄,
  • methods部分的一些方法被重写,内部会调用 invoke
  • 最先面是常量池的信息


再继续,我们在深入的看一下 $Proxy0 产生的实例包含了什么信息

 

可以看到$Proxy0实例 关联了一个 MyInvoke实例 。然后MyInvoke实例 关联了 目标对象 TargetImp

 

总结:

动态代理就是根据目标对象,产生一个 和目标对应拥有共同接口 且 继承了Proxy类的 类。

具体代理逻辑,交给InvocationHandler 的实现类去处理。

posted @ 2018-05-25 14:47  torjan  阅读(229)  评论(0编辑  收藏  举报