动态代理与拦截器的实现原理剖析
这是我第二个博客其中的一篇文章。
下面是原文(未大改,稍作了一些格式上的调整):
对动态代理的学习是从Struts 2的拦截器的学习引出来的,Struts 2的拦截器的实现即借用了动态代理,于是我又Google了一下动态代理的实现原理,看了几段代码,但终究对程序的运行原理似懂非懂,为彻底弄清动态代理的原理,我阅读了 java.lang.reflect.Proxy 类的源代码。
Proxy类中有两个关键方法,一个是:
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
另一个是:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
在 newProxyInstance() 中调用了 getProxyClass() ,但在 getProxyClass() 中由于native方法 defineClass0() 的存在,对这段代码的研究也未能彻底弄懂,不过还是大致弄懂了它的作用:程序传给它一个类加载器,若干个接口,它的作用就是利用这个类加载器,动态生成一个实现这若干个接口的类,并返回。
下面再看 newProxyInstance() 方法,它有如下关键代码(其中省略了必要的try-catch语句块):
Class cl = getProxyClass(loader, interfaces);
Constructor cons = cl.getConstructor(constructorParams);
// constructorParams的定义为:private final static Class[] constructorParams = {InvocationHandler.class};
return (Object)cons.newInstance(new Object[]{h});
可看出它首先是得到一个实现了参数中所列接口的类,通过第二句代码,可以猜出该类必定有一个构造方法为: public Proxy(Class[]{InvocationHandler h}) ,通过第三句代码可以猜出,该类中定义了一个字段为: private InvocationHandler h; ,并且将参数中的InvocationHandler的一个引用传给该字段以创建一个新实例,然后返回该实例。
从动态代理的作用可以猜出,这个返回类实现的所有方法,必定都只有一句代码: return h.invoke(this, ..., ...); 即所有方法都只调用了InvacationHandler实例的invoke方法,当然这个类中还要处理如何获得相应方法的封装类Method以及其形参args(Object[]类型),并且作为参数传递给invoke()。
好了,既然原理搞清楚了,下面就来做一个动态代理的实现示例:
package ini.always.DynamicProxy;
import java.lang.reflect.*;
interface Logic
{
public void doSomeBusinessLogic();
}
class BusinessLogic implements Logic
{
public void doSomeBusinessLogic()
{
System.out.println("in method doSomeBusinessLogic()");
}
}
class ProxyHandler implements InvocationHandler
{
private Object target;
public ProxyHandler(Object target)
{
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Exception
{
Object result;
before();
result = method.invoke(target, args);
after();
return result;
}
private void before()
{
System.out.println("before method doSomeBusinessLogic()");
}
private void after()
{
System.out.println("after method doSomeBusinessLogic()");
}
}
public class TestProxy
{
public static void main(String[] args)
{
Logic logic = new BusinessLogic();
InvocationHandler h = new ProxyHandler(logic);
Logic proxy = (Logic) Proxy.newProxyInstance(Logic.class.getClassLoader(),logic.getClass().getInterfaces(), h);
proxy.doSomeBusinessLogic();
}
}
编译后运行,程序将输出:
before method doSomeBusinessLogic() in method doSomeBusinessLogic() after method doSomeBusinessLogic()
这就是动态代理和拦截器的实现原理。
Generated by Emacs 24.5.1 (Org mode 8.x)
Copyright © 2014 - Kelvin Hu - Powered by org-page
Themed with emacs_love