为什么叫动态代理,个人理解是代理的类是在运行时动态生成的,
开门见山,lets go..
java中可以通过jdk提供的 Proxy.newProxyInstance静态方法来创建动态代理对象,下面先来看看这个方法的实现
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //InvocationHandler不能为空,因为对代理对象的所有方法调用实际上都会委托到InvocationHandler的invoke方法, //这个我们后面通过查看产生的代理类的源代码便会一目了然 if (h == null) { throw new NullPointerException(); } //这个是核心的地方,通过提供的ClassLoader和interface列表来产生代理类,具体的实现可以参考getProxyClass这个方法的实现, //真正的工作是由sun.misc.ProxyGenerator这个类来完成的,可以google查看具体的逻辑.在我们的程序中通过设置 //System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")可以查看产生的类文件 Class cl = getProxyClass(loader, interfaces); //因为代理类继承了Proxy类.而Proxy中定义了构造函数protected Proxy(InvocationHandler h),所以可以反射得到Constructer实例 //创建代理对象 try { Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }
下面通过个例子来说明下:
先来定义一个接口,jdk的动态代理基于接口来创建代理类,不能基于类的原因是java不支持多重继承,而代理类都会继承Proxy类(个人理解).
/** * Subject * * @author Kevin Fan * @since 2013-9-13 下午2:43:33 */ public interface Subject { void pub(String key, String content); String sub(String key); }
再来一个具体的实现,在代理模式中可以叫它的实例可以叫target,这个是真正执行操作的对象
/** * SimpleSubject * * @author Kevin Fan * @since 2013-9-13 下午2:45:03 */ public class SimpleSubject implements Subject { private Map<String, String> msg = new ConcurrentHashMap<String, String>(); public void pub(String key, String content) { System.out.println("pub msg: key is " + key + ", content is " + content); msg.put(key, content); } public String sub(String key) { if (msg.containsKey(key)) { String ret = msg.get(key); System.out.println("sub msg: key is " + key + ", result is " + ret); return ret; } return null; } }
好,接下来我们来写个动态代理工厂,根据 不同的target来创建动态代理对象
/** * SubjectProxyFactory * * @author Kevin Fan * @since 2013-9-13 下午2:47:24 */ public class SubjectProxyFactory { //TODO: cache public static Subject getSubject(final Subject realSubject) { return (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), new Class[] { Subject.class }, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("\naction before method invocation...."); Object retVal = method.invoke(realSubject, args); System.out.println("action after method invocation....\n"); return retVal; } }); } }
可以看到这是一个简单的实现,只是在真实对象执行前后各打一句信息..
接下来用一个 main函数来把这些结合起来
- =
/** * Demo * * @author Kevin Fan * @since 2013-9-13 下午2:50:28 */ public class Demo { public static void main(String[] args) { //设置此系统属性,以查看代理类文件 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //创建真实对象 Subject subj = new SimpleSubject(); subj.pub("name", "kevin.fan"); subj.sub("name"); //创建代理对象 Subject proxy = SubjectProxyFactory.getSubject(subj); proxy.pub("hobby", "r&b music"); proxy.sub("name"); } }
ok,小手抖一下,走你,看下执行结果
pub msg: key is name, content is kevin.fan sub msg: key is name, result is kevin.fan action before method invocation.... pub msg: key is hobby, content is r&b music action after method invocation.... action before method invocation.... sub msg: key is name, result is kevin.fan action after method invocation....
可以看到在调用代理对象的方法时,添加的额外动作已经生效,接下来我们看下生成的代理类的代码..
import com.aliyun.demo.kevin.coder.lang.proxy.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; //这里很清楚了,代理类继承了Proxy类,并且实现了Proxy.newProxyInstance这个方法中传入的接口
public final class $Proxy0 extends Proxy implements Subject { //这些方法在下面的static init block中进行初始化 private static Method m4; private static Method m1; private static Method m3; private static Method m0; private static Method m2; static { try { m4 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("sub", new Class[] { Class.forName("java.lang.String") }); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("pub", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } //构造函数,接收一个 InvocationHandler作为参数,这就是为什么Proxy.newProxyInstance方法里可以 //通过InvocationHandler实例作为参数来反射获取Constructer实例 public $Proxy0 paramInvocationHandler) throws { super(paramInvocationHandler); } //下面通过这个来看下代理对象中方法是怎样调用的 public final String sub(String paramString) throws { try { //全部是通过调用InvocationHandler的invoke方法,传入对应的方法和参数 return (String)this.h.invoke(this, m4, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final boolean equals(Object paramObject) throws { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void pub(String paramString1, String paramString2) throws { try { this.h.invoke(this, m3, new Object[] { paramString1, paramString2 }); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } }