代理模式

首先,什么是代理,拿出你的手机,打开微信朋友圈,看看朋友圈的微商,这就是代理。代理就是一个对象代表代表另一个对象做其需要做的事,就像刚才说的微商,你的朋友就是代理了原厂商。现在大概知道了代理是什么,那么Android中有哪些代理呢,举个最简单的例子,我们都知道Context,Context就是使用了代理模式,ContextImpl实现了Context的所有功能,ContextWrapper即为代理类,也实现了Context类,里面包含的Context引用为ContextImpl,所以ContextWrapper调用的方法都是ContextImpl中的实现,这就是典型的代理模式。

动态代理

我们知道代理模式需要自己创建代理类,代理所有方法,简单的说,这就是静态代理,上述的Context的代理模式就是静态代理。那么动态代理是什么,简单的说就是不需要自己创建代理类,而是动态生成。废话不多说直接上代码,首先先创建一个接口抽象出需要的所有功能:

1
2
3
public interface Action{
void doWork();
}

接口很简单,只有一个方法doWork(),接下来我们创建委托类,也就是具体实现功能的类:

1
2
3
4
5
public class RealAction implements Action{
@Override public void doWork() {
Log.e("wcwcwc", "RealAction : doWork()");
}
}

接下来就是我们的今天的重点了,创建代理处理器,我们需要创建一个实现InvocationHandler接口的类,如下:

1
2
3
4
5
6
7
8
public class TestDynamicProxy implements InvocationHandler {
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("wcwcwc", "proxy: " + proxy.getClass().getCanonicalName() + "\n" +
"method: " + method + "\n" +
"args: " + args);
return null;
}
}

先不解释这个类,直接看怎么使用,代码如下:

1
2
Action action = (Action) Proxy.newProxyInstance(RealAction.class.getClassLoader(), new Class[]{Action.class}, new TestDynamicProxy());
action.doWork();

此时,我们就完成了一次动态代理调用,但是上面的代码是有问题的,现在就相当于使用没有给ContextWrapper传入ContextImplContextWrapper,也就是说缺少委托。对于上面的例子来说就是缺少RealAction类的引用,对代码做如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestDynamicProxy implements InvocationHandler {
Object target;
public TestDynamicProxy(Object target){
this.target = target;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("wcwcwc", "proxy: " + proxy.getClass().getCanonicalName() + "\n" +
"method: " + method + "\n" +
"args: " + args);
Object result = method.invoke(target, args);
return result;
}
}

1
2
3
RealAction realAction = new RealAction();
Action action = (Action) Proxy.newProxyInstance(RealAction.class.getClassLoader(), new Class[]{Action.class}, new TestDynamicProxy(realAction));
action.doWork();

如上所示,我们下面执行action.doWork()后,就会打印RealAction : doWork()也就是RealActiondoWork()方法的实现。下面我们逐一说明一下每个方法的作用。

我们先看上面修改后的TestDynamicProxy代理类,它实现了InvocationHandler接口的invoke方法,该方法有三个参数,返回值为Object,其中第一个参数为动态生成的代理类对象,第二个参数为当前执行的方法,第三个参数为当前执行方法的参数,返回值当然就是当前执行方法的返回值了,所以就上上面代码一样,target就是委托,所以调用代理类的方法时候,调用target的相关方法,也就是执行TestDynamicProxy类中第10行的代码。

然后在看下面的Proxy.newProxyInstance()方法,这个方法主要是生成代理类,所以我们可以把它强转为Action。这个方法也有三个参数,第一个参数为类加载器,第二个是代理类需要实现的所有接口,第三个参数为InvocationHandler。我们在第三个参数中传入了RealAction类的引用,达到了最终的动态代理效果。我们就可以肯据自己的业务需求在执行代理方法前或者后做相关的操作了,也就是在invoke方法中实现。

$Proxy0

$Proxy0是什么,$Proxy0就是动态生成的代理类,该类继承Proxy,并实现newProxyInstance()第二个方法的所有接口。该代理类反射了所有实现接口的方法,在调用目标方法时,调用InvocationHandlerinvoke()方法,传入相关参数,因为该类继承Proxy,Proxy中有InvocationHandler成员变量,该变量在实例化的时候被赋值所以$Proxy0就可以调用InvocationHandlerinvoke方法了。

值得注意的是,$Proxy0类除了反射实现接口的所有方法,还反射了java.lang.Objectequals方法,hashCode方法和toString方法,并和实现的接口一样,重写这三个方法,在方法体中通过InvocationHandler调用invoke()并传入反射的method。所以我们在测试动态代理代码的时候,切记不要调用这几个方法,比如在InvocationHandlerinvoke()方法中不要调用类似如下的代码:

1
Log.e("wcwcwc", "proxy: " + proxy);

因为上述方法会调用proxytoString方法,上面我们说了toString方法也会调用invoke方法,所以就会出现死循环,因为newProxyInstance最终会调用JNIgenerateProxy方法,所以可能会出现类似JNI local reference table overflow (max=512)的异常,也就是JNI局部引用表溢出的异常。