动态代理与拦截器的实现原理剖析
这是我第二个博客其中的一篇文章。
下面是原文(未大改,稍作了一些格式上的调整):
对动态代理的学习是从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