探索JAVA动态代理机制

      曾几何时本人对Spring AOP感到神秘莫测,无比膜拜。感叹它的拦截功能无所不能,感叹它一统天下的 雄心壮志!上周闲来无事,索性也来拦截一把!开始做起了代理商。。。

      说到AOP不得不说到代理模式,说到代理模式又不禁联想到Java动态代理。正如你说猜想的,解决了Java动态代理机制Sping AOP也不再是神话!现在开始探索Java动态代理机制先。。。

      首先请看java.lang.reflect下有个proxy,不管三七二十几把它晒晒再说。(详细代码参见:java.lang.reflect.Proxy.java)顾名思义,这就是代理的真正元凶! Proxy元凶有如下特征:

          -String proxyClassNamePrefix = "$Proxy"; // 代理类名前缀

          -Class[] constructorParams = {InvocationHandler.class}; // 代理类构造函数参数列表

          -Map   loaderToCache = new WeakHashMap(); // 缓存代理类加载器

          -Object pendingGenerationMarker = new Object(); // 标记代理实例是否被创建

          -Map proxyClasses = Collections.synchronizedMap(new WeakHashMap()); // 缓存代理实例

          protected InvocationHandler h;  // 引用调用处理程序对象

Proxy元凶有如下罪行:  

private Proxy(){} // 构造器私有化   protected Proxy(InvocationHandler h){this.h = h}

       注:红色标注表明它是团伙作案的。它一人是不能完成的,至少二人以上作案。

      + isProxyClass(Class<?> clazz); // 判定是否是代理类

      + getInvocationHandler(Object proxy);// 获取指定代理实例的调用处理程序。

      + newProxyInstance(ClassLoader loader , Class<?>... interfaces); // 获取代理实例

      + getProxyClass(ClassLoader loader , Class<?> ... interfaces) // 获取代理类

如果注意该类doc信息,你不难发现创建proxy有两种方式:

Method 1:

InvocationHandler handler = new MyInvocationHandler(...);   
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });   
Foo f = (Foo) proxyClass.getConstructor(new Class[]  {InvocationHandler.class }).newInstance(new Object[] { handler }); 
Method 2:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] {Foo.class },handler);  

      很明显,大家都喜欢简单明了的第二种方式。其实第二种方式就是对一种方式的封装。看来sun为我们考虑的还是蛮周到的嘛~大家看newProxyInstance方法如此简单,不就是获取到代理类,然后根据反射机制生成代理实例而已。没错,重头戏还是如何获取代理类,如何将委托的信息交给代理类呢?我们就需要分析一下getProxyClass~进入该方法刚开始也就是做一些安全之类的检测(被代理类是否是接口类型,包名检查。。。),当你看到这里就要注意了!

      

String proxyName = proxyPkg + proxyClassNamePrefix + num; // 生成类名 eg com.proxy.demo$Proxy1   
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces); //生成代理接口字节码   
proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); // 将生成的代理接口字节码注入到类加载器中 

       由于 denfineClass0属于本地代码,如名字一样也就是生成类信息。你可以理解为将生成的代理接口字节码注入到类加载器中,动态生成代理类。那么关键问题就在ProxyGenerator.generateProxy了,可是sun并未提供源码,不过也没有关系,我们可以模拟实现嘛!预知后事如何,参见模拟实现Java动态代理机制 !

你可能感兴趣的:(代理模式,java动态代理)