黑马程序员 动态代理

来源:互联网 发布:如何供货给淘宝 编辑:程序博客网 时间:2024/06/05 15:24
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

动态代理技术其实并不复杂,它是一个面向方面的程序设计,简单点说,就是不是针对一种特定的方法而设计。比如很多系统中都要记录安全信息、事物信息、生成日志,我们不可能一个方法一个方法的往上加代码吧,那样累赘而麻烦。这就需要用到一个类代理需要的类,然后再代理类中使用我们需要的方法,只要加上了代理类,再调用其中的所有方法都是调用我们代理类上自己定义的方法,这样就实现了面向方面程序设计。


AOP(Object Oriented Programming):

在实际的网络中,我们也很少直接使用需要客服端的信息,中间都需要加载一个代理,这样方便与操作。



代理类的建立:

既然是代理一个类,那么我们肯定无法确定需要代理的是什么类,而又要用到那个类中的方法,这肯定是使用了反射。

代理类的建立,必须得到与需要使用类有关联的代理类的Class文件对象。

通过Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces);

它必须要接收一个类加载器,和要实现代理接口的Class对象。


既然要使用Proxy这个类,就必须查看其中的构造方法、函数方法。

既然能得到Proxy的Class对象,不妨用反射列出其中的方法,可用如下方法做:

System.out.println("-------------------Proxy Method-----------------------------");//通过反射返回类中方法数组Method[] methods = clazzProxy.getMethods();for(Method method: methods){String name = method.getName();StringBuilder sb = new StringBuilder(name);sb.append("(");//得到每个方法的参数,通过 getParameterTypes() 方法Class[] clazzParams = method.getParameterTypes();//将参数加入一个StringBuilder,并按照格式打印for(Class clazzParam: clazzParams){sb.append(clazzParam.getName()).append(",");}if(clazzParams.length!=0)sb.deleteCharAt(sb.lastIndexOf(","));sb.append(")");System.out.println(sb.toString());}
同理得到构造方法,打印结构发现Proxy只有一个构造方法
com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
其中的方法有:
-------------------Proxy Method-----------------------------hashCode()equals(java.lang.Object)toString()add(java.lang.Object)contains(java.lang.Object)isEmpty()size()toArray()toArray([Ljava.lang.Object;)addAll(java.util.Collection)iterator()remove(java.lang.Object)clear()containsAll(java.util.Collection)removeAll(java.util.Collection)retainAll(java.util.Collection)isProxyClass(java.lang.Class)getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)getInvocationHandler(java.lang.Object)getClass()notify()notifyAll()wait(long)wait(long,int)wait()
大多都是Object类中方法,其中的newProxyInstance建立实例的方法也与InvocationHandler有关,可以推测动态代理主要是通过此方法来实现的。


查看API文档可知,newProxyInstance()返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。就是说创建出了这个代理,就能完全实现原有接口中的所有功能。那么既然这个是个代理类,当然也可以自己添加新的功能进去,这便是动态代理了,只要我们需要,完全可以加载自己想要方法进去。

下面是一个用动态代理植入广告的程序,我们也可以随意更换其中的广告内容:

这是一个sayHello的接口:

package cn.itcast.day3;public interface SayHello {void sayHello();}
此类实现了sayHello接口,也是我们需要代理的类,在其收尾植入广告:
package cn.itcast.day3;public class TestSayHello implements SayHello {public void sayHello() {System.out.println("Hello sky!");}}
创建一个代理对象,并加入植入语句:
package cn.itcast.day3;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyTest {public static void main(String[] args) throws Exception{Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);//将接口定义成目标类final TestSayHello target = new TestSayHello();// 抽取出获取代理的方法,并调用之SayHello proxy2 = (SayHello)getProxy(target, new Test());  proxy2.sayHello();}private static Object getProxy(final Object target, final Test test) {//newProxyInstance接收3个参数 ClassLoader, Interfaces, InvocationHandlerObject proxy2 = Proxy.newProxyInstance(target.getClass().getClassLoader(),  target.getClass().getInterfaces(),  //实现InvocationHandler中的inovke方法  new InvocationHandler() {//invoke接收的3个参数实际上就是需要代理类中对象、方法、参数public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {test.beforeMethod();//调用方法前加入的植入Object obj = method.invoke(target,args);test.behindMethod(method);  //调用方法前加入的植入return obj;}});return proxy2;}}
最后写需要植入的内容:
package cn.itcast.day3;import java.lang.reflect.Method;public class Test {long startTime = 0;public void beforeMethod(){System.out.println("我是插入的广告");startTime = System.currentTimeMillis();}//返回调用此方法使用的时间public void behindMethod(Method method){long endTime = System.currentTimeMillis();System.out.println(method.getName()+":runtime--"+(endTime-startTime));}}
打印结果:
我是插入的广告Hello sky!sayHello:runtime--0
成功植入广告,并打印出时间,知道这个动态代理的原理后,以后再使用相同的方法时候就简单的多,并且之后的框架如ssh都是基于动态代理产生的,有助于我们理解框架的构建。











---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
0 0
原创粉丝点击