黑马程序员——Java中的动态代理

来源:互联网 发布:aes256 加密java代码 编辑:程序博客网 时间:2024/05/08 15:35

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ---------------------

代理也是基本的设计模式之一,而代理通常也作为一种中介对象。

Java的动态代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理的方法的调用。在动态代理上所做的所有的调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。


下面就以一个创建动态代理类和查看的方法的代码来看看吧:

首先我们来定义下两个接口:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.itcast.day3;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. public interface Advice {  
  6.      void beforeMethod(Method method);//定义之前的接口  
  7.      void afterMethod(Method method);//定义之后的接口  
  8. }  

接下来呢  就是实现我们定义的接口:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.itcast.day3;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. public class MyAdvice implements Advice {  
  6. long beginTime=0;  
  7.     @Override  
  8.     public void beforeMethod(Method method) {  
  9.         // TODO Auto-generated method stub  
  10.         System.out.println("开始学习啦!");  
  11.         beginTime=System.currentTimeMillis();//定义开始时间(毫秒)  
  12.     }  
  13.   
  14.     @Override  
  15.     public void afterMethod(Method method) {  
  16.         // TODO Auto-generated method stub        
  17.         System.out.println("开始上班啦!");  
  18.         long endTime=System.currentTimeMillis();//定义结束时间(毫秒)  
  19.         System.out.println(method.getName()+"运行时间为"+(endTime-beginTime)+"毫秒");  
  20.     }  
  21.   
  22. }  
下一步我们来调用实现接口的方法 :


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.itcast.day3;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.InvocationHandler;  
  5. import java.lang.reflect.Method;  
  6. import java.lang.reflect.Proxy;  
  7. import java.util.ArrayList;  
  8. import java.util.Collection;  
  9.   
  10. /*创建动态代理类及查看其方法*/  
  11. public class ProxyTest {  
  12.     public static void main(String[] args) throws Exception {  
  13.         Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);  
  14.         System.out.println(clazzProxy1.getName());  
  15.         System.out.println("-------begin constructors lists--------");  
  16.         Constructor[] constructors=clazzProxy1.getConstructors();  
  17.         for(Constructor constructor : constructors){  
  18.             String name=constructor.getName();  
  19.             StringBuilder sBuilder=new StringBuilder(name);  
  20.             sBuilder.append('(');  
  21.             Class[] clazzParams=constructor.getParameterTypes();  
  22.             //把构造函数里面的值取出来  
  23.             for(Class clazzParam : clazzParams){  
  24.                 sBuilder.append(clazzParam.getName()).append(',');  
  25.             }  
  26.             if(clazzParams!=null&&clazzParams.length!=0)  
  27.                 sBuilder.deleteCharAt(sBuilder.length()-1);  
  28.             sBuilder.append(')');  
  29.             System.out.println(sBuilder.toString());  
  30.         }  
  31.         System.out.println("-------begin Method lists--------");  
  32.         Method[] methods=clazzProxy1.getMethods();  
  33.         for(Method method : methods){  
  34.             String name=method.getName();  
  35.             StringBuilder sBuilder=new StringBuilder(name);  
  36.             sBuilder.append('(');  
  37.             Class[] clazzParams=method.getParameterTypes();  
  38.             //把构造函数里面的值取出来  
  39.             for(Class clazzParam : clazzParams){  
  40.                 sBuilder.append(clazzParam.getName()).append(',');  
  41.             }  
  42.             if(clazzParams!=null&&clazzParams.length!=0)  
  43.                 sBuilder.deleteCharAt(sBuilder.length()-1);  
  44.             sBuilder.append(')');  
  45.             System.out.println(sBuilder.toString());  
  46.         }  
  47.         //创建实例对象,接收InvocationHandler对象  
  48.         System.out.println("-------begin instance Object--------");  
  49.         //Object obj=clazzProxy1.newInstance();如果这样写,运行时就会出错。所以要先得到构造函数  
  50.          Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);  
  51.         //新建一个自己的实现类,实现InvocationHandler接口  
  52.         class MyInvocationHandler implements InvocationHandler{  
  53.   
  54.             @Override  
  55.             public Object invoke(Object proxy, Method method, Object[] args)  
  56.                     throws Throwable {  
  57.                 // TODO Auto-generated method stub  
  58.                 return null;  
  59.             }  
  60.         }  
  61.             Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler());  
  62.             System.out.println(proxy1);  
  63.             proxy1.clear();//调用无返回值的方法就会成功  
  64.             //proxy1.size();//这里会报空指针异常,size()方法有返回值  
  65.             Collection proxy2=(Collection)constructor.newInstance(new InvocationHandler(){  
  66.                 @Override  
  67.                 public Object invoke(Object proxy, Method method, Object[] args)  
  68.                         throws Throwable {  
  69.                     return null;  
  70.                 }                 
  71.             });  
  72.             final ArrayList target=new ArrayList();  
  73.             Collection proxy3 =(Collection)getProxy(target,new MyAdvice());  
  74.             proxy3.add("a");  
  75.             proxy3.add("b");  
  76.             proxy3.add("c");  
  77.             System.out.println(proxy3.size());  
  78.           
  79.     }  
  80.   
  81.     private static Object getProxy(final Object target,final Advice advice) {  
  82.         Object proxy3=Proxy.newProxyInstance(  
  83.                 target.getClass().getClassLoader(),  
  84.                 //new Class[]{Collection.class},  
  85.                 target.getClass().getInterfaces(),  
  86.                 new InvocationHandler() {                         
  87.                     public Object invoke(Object proxy, Method method, Object[] args)  
  88.                             throws Throwable {  
  89.                         //ArrayList target=new ArrayList();如果这句话在invoke方法内,就会输出0,无法获取数量  
  90.                         /*long beginTime=System.currentTimeMillis();//定义开始时间(毫秒) 
  91.                         Object reVal=method.invoke(target, args); 
  92.                         long endTime=System.currentTimeMillis();//定义结束时间(毫秒) 
  93.                         System.out.println(method.getName()+"运行时间为"+(endTime-beginTime)+"毫秒"); 
  94.                         return reVal;*/  
  95.                           
  96.                         advice.beforeMethod(method);  
  97.                         Object reVal=method.invoke(target, args);  
  98.                         advice.afterMethod(method);                           
  99.                         return reVal;  
  100.                     }  
  101.   
  102.                       
  103.                 }  
  104.                 );  
  105.         return proxy3;  
  106.     }  
  107. }  

上面的代码中若创建一个动态代理的类,就要实现InvocationHandler接口。

因为动态代理类可以将所有调用重定向到处理器,所以通常会向调用处理器的构造器传递给一个“实际”对象的引用,使得调用处理器在执行中介任务时,可以将请求转发。

invoke()方法中传递进来代理对象,用于以防止你需要区分请求的来源。当然也可以传递其他的参数来过滤某些方法的调用。



----------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com

0 0
原创粉丝点击