谈谈自己对动态代理的理解,举个例子,
你现在有需求,需要把字串符"abc"放到一个集合里,
我们可以这样做:
用new的方式创建一个集合
List list = new ArrayList();
然后调用add方法把字符串放进去
list.add("abc");
那么,用动态代理怎么做呢,和上面很相似:
List proxyList = ……;
proxyList.add("abc");
省略号的内容暂且不表,可以看出,动态代理其实就是换种方式来完成目的罢了,
并且在达成目的的同时可以加上访问控制或者额外功能,上面的list.add完成的仅仅是要求的添加字符串功能,
而下面的proxyList.add,我们可以让它完成添加功能的同时具备别的能力,比如显示方法名,用的时间等等
那么省略号到底是什么呢?就是生成这个动态代理类的方法:
List proxyList = (List) Proxy.newProxyInstance(List.class.getClassLoader(), new Class[] { List.class },
new InvocationHandler() {
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " running time is " + (endTime - startTime) + " millisecond.");
return retVal;
}
});
proxyList.add("abc");
执行结果:加入数据,并显示add running time is 0 millisecond.
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这个方法看上去比较吓人,参数列表这么长,一一道来:(三个参数)
ClassLoader loader:一个类加载器,不用多说了
Class<?>[] interfaces:含有目的方法的接口数组,怎么理解呢?拿上面的例子说,你想要一个ArrayList,用它add方法添加字符串,
而add方法是ArrayList实现的接口List中的方法,所以要让代理类拥有同样功能的话,要把List包含进去
InvocationHandler h: 这是代理实例的调用处理程序 实现的接口。该接口中只有 Object invoke(Object proxy, Method method, Object[] args) 方法,
该方法 在代理实例上处理方法调用并返回结果。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,
将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。
简单的讲,上面的add方法就是在这个InvocationHandler实例里的invoke方法里实现的(Object retVal = method.invoke(target, args);)
真正实现add方法的是封装在 InvocationHandler 实例中的ArrayList对象,这是一个双重invoke
这样就生成了一个实现List接口的动态代理类。