在上一章我们看到了,新增的三种类都能实现对原始功能类进行添加功能的事务处理,这三种类就是一个代理。
但是这种代理是写死的,怎样实现对任意接口添加自定义的代理呢?
我们先来看一下之前的代理实现:
1 public class Impeat { 2 private InterfaceDo todo; 3 public Impeat(InterfaceDo todo) { 4 super(); 5 this.todo = todo; 6 } 7 public void dothings() { 8 todo.dosomething(); 9 System.out.println("我要吃饭了啊--------"); 10 } 11 }
因为这里我们的代理不需要再被其他代理引用,所以就不需要实现InterfaceDo接口,自然内部方法也是可以自定义,没有必要
遵循InterfaceDo的方法定义,为了避免混淆,我们将其改为了dothings(),由于代理类都是这样的一个书写模式:定义成员变量、
构造函数为成员变量赋值为代理对象、自定义方法实现对代理对象方法的调用。我们索性定义一个接口,以后所有的代理类都按
照统一模式来写,在JDK中就定义了这样的一个接口InvocationHandler,我们的代理类都实现这个接口,遵循它的书写方式,
下面我们再来看看代理类里面的元素:
InterfaceDo:需要代理对象的实现接口;
todo:需要代理的对象;
红字:为代理对象添加的功能实现;
todo.dosomething():代理对象的原始功能。
既然要实现动态代理,那么这个代理实现的部分源码,就不能写死了(被代理对象的接口、被代理的对象以及被代理对象内部的
方法),接口我们可以自定义,被代理对象我们可以new出来,但是被代理对象内部的方法是不确定的,A代理对象可能是A方法,
B代理对象可能是B方法,C代理对象可能是C方法。
所以,我们要动态获取代理对象的内部方法就得通过反射来获得。
被代理对象的方法怎么获得呢?由于被代理对象是实现了接口的,被代理对象的内部方法必定也是重写自接口的定义方法的。那么
我们就可以从接口入手,获取接口的方法定义。
来看看JDK的实现:
public class Handlerimp implements InvocationHandler { private Object obj; public Handlerimp(Object obj) { super(); this.obj = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----我要实现新的功能-----"); Object returnValue = method.invoke(obj, args); return returnValue; } }
是不是很眼熟,对,这个和我们之前的静态代理实现模式一样。只不过底层已经用反射帮我们获得了被代理对象obj的方法method
以及方法的参数数组,然后通过被代理对象、方法、参数三者来执行被代理对象的方法-------method.invoke(proxy,args)。
接下来,我们实例化一个该代理类的实例:
public class Testperson { public static void main(String[] args) { InterfaceDo a = new Persontodo(); Handlerimp handler =new Handlerimp(a); ClassLoader loader = a.getClass().getClassLoader(); Class[] interfaces = a.getClass().getInterfaces(); InterfaceDo subject = (InterfaceDo) Proxy.newProxyInstance(loader, interfaces, handler); subject.dosomething(); subject.dothing(); } }
我们可以看到,JDK中通过Proxy类的静态方法newProxyInstance()获得代理类实例;
该方法实现了对被代理对象所有方法的遍历,因此实现了对被代理对象所有方法的功能添加。
之后,我们就可以调用代理类的方法了。