深入理解JAVA JDK动态代理机制

来源:互联网 发布:日本创业公司数据库 编辑:程序博客网 时间:2024/06/05 17:05

一、现实生活中的代理?

        在现实生活中,我们常见的有服务器代理商、联想PC代理商、百事可乐、火车票、机票等代理商,为什么会有这些个代理商呢?设想以买火车票为场景,如果我要买一张从广州去长沙的火车票,就必须去火车站排队购票,如果排队的人比较多的话,非常的耽误时间。但有了火车票代理商之后,我就可以直接去找个离我最近的代理商买票,因为这样的代理商不止一个二个,遍布全市各地。 所以代理商的出现不但减轻了火车站售票员的工作压力,同时也为市民购票提供了许多方便。只是代理商会收5块的手续费。从这个示例中可以发现和买票有关的一些名词:火车站、售票、代理商?解释这些名词在程序中代理的含义:火车站:称为目标,售票:目标的最终行为,代理商:和火车站具有同样售票行为的代理商,不过代理商在售票前和售票后会做一些操作,比如查询余票、售票后收取手续费等操作。

二、JDK中的代理

1、特征:
      1)、jdk中代理的一个很重要的特征:代理类和目标类都拥有相同的接口,所以它们都拥有相同的行为。代理类的对象本身并不真正提供服务,而是调用目标类对象的相关方法,来提供特定的服务。如:火车票代理商自己并不提供火车票销售的服务,而是调用火车站的售票服务。为顾客提供查询余票信息、火车的运营时间、火车票的销售等服务,这些服务都是来自火车站(目标类)。代理类主要负责为目标类预处理消息(如:身份证信息是否正确)、过滤消息(如:该顾客是否为通缉犯,是否公安监视的人),并把这些消息转发给目标类,以及事后处理消息(收取顾客的手续费)等。
      2)、必须实现一个或多个接口

2、代理种类:

1)、静态代理,示例:以销售火车票为例

a、定义一个火车站售票的接口
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. public interface Ticket { 
  4.  
  5.     public void ticket(); 
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. public interface Ticket {  
  4.   
  5.     public void ticket();  
  6. }  
b、售票接口的实现类
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. public class TicketImpl implements Ticket { 
  4.  
  5.     @Override 
  6.     public void ticket() { 
  7.         System.out.println("成功售出一张火车票!"); 
  8.     } 
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. public class TicketImpl implements Ticket {  
  4.   
  5.     @Override  
  6.     public void ticket() {  
  7.         System.out.println("成功售出一张火车票!");  
  8.     }  
  9. }  
c、火车票销售的代理类,与目标类实现了相同的接口
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. /**
  4. * 火车票销售代理类
  5. */ 
  6. public class TicketImplProxy implements Ticket { 
  7.      
  8.     private TicketImpl ticketImpl;  //目标类 
  9.      
  10.     public TicketImplProxy(TicketImpl ticketImpl) { 
  11.         this.ticketImpl = ticketImpl; 
  12.     } 
  13.  
  14.     @Override 
  15.     public void ticket() { 
  16.         System.out.println("售票前验证顾客的身份信息…………"); 
  17.         ticketImpl.ticket(); 
  18.         System.out.println("售票后收取顾客的手续费…………"); 
  19.     } 
  20.  
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. /** 
  4.  * 火车票销售代理类 
  5.  */  
  6. public class TicketImplProxy implements Ticket {  
  7.       
  8.     private TicketImpl ticketImpl;  //目标类  
  9.       
  10.     public TicketImplProxy(TicketImpl ticketImpl) {  
  11.         this.ticketImpl = ticketImpl;  
  12.     }  
  13.   
  14.     @Override  
  15.     public void ticket() {  
  16.         System.out.println("售票前验证顾客的身份信息…………");  
  17.         ticketImpl.ticket();  
  18.         System.out.println("售票后收取顾客的手续费…………");  
  19.     }  
  20.   
  21. }  
d、测试类:
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. public class StaticProxyTest { 
  4.  
  5.     public static void main(String[] args) throws Exception { 
  6.         TicketImpl ticketImpl = new TicketImpl();   //要代理的目标 
  7.         TicketImplProxy staticProxy = new TicketImplProxy(ticketImpl); 
  8.         staticProxy.ticket(); 
  9.     } 
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. public class StaticProxyTest {  
  4.   
  5.     public static void main(String[] args) throws Exception {  
  6.         TicketImpl ticketImpl = new TicketImpl();   //要代理的目标  
  7.         TicketImplProxy staticProxy = new TicketImplProxy(ticketImpl);  
  8.         staticProxy.ticket();  
  9.     }  
  10. }  

运行结果:


静态代理的缺陷:
    一个代理类只能代理一个目标类,如果在一个系统中想代理多个目标类的话,就得写多个代理类,这将是一件很繁琐的工作。所以在JDK1.3之后,引出了动态代理的概念,动态代理可以在程序运行的时候,通过反射机制动态的生成一个类的字节码文件,并实现目标类相同的接口。

2)、动态代理
1)、介绍:
    jdk中的动态代理,主要用到了java.lang.reflect包中的两个类:Proxy类InvocationHandler接口,Proxy类用于生成代理类,InvocationHandler接口用于调用目标类的方法之前或之后,做一些处理。比如:记录日志、事务处理、效率测试等,均在该接口的invoke方法中实现。传说中AOP思想的原理就是从这里开始扩展的。



2)、动态代理机制深入分析(以ArrayList为代理目标类为例):
1、使用Proxy类的getProxyClass方法,获得ArrayList代理类的字节码文件
[java] view plaincopyprint?
  1. Class clazzProxy = Proxy.getProxyClass(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces()); 
[java] view plaincopyprint?
  1. Class clazzProxy = Proxy.getProxyClass(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces());  
2、打印代理类的结构信息
获得这个Class对象的字节码文件之后,我们打印出来看看这个类的名字叫什么?
[java] view plaincopyprint?
  1. System.out.println("代理类名称:" + clazzProxy.getName()); 
[java] view plaincopyprint?
  1. System.out.println("代理类名称:" + clazzProxy.getName());  
代理类名称:$Proxy0
通过JDK反射机制,获代理类的结构,比如:它的父类是谁?实现了哪些接口?有哪些个构造方法?有哪些个成员方法?等。。。
下面将通反射机制,获取这个代理类的组织结构信息:
[java] view plaincopyprint?
  1. System.out.println("代理类" + clazzProxy.getName() + "的父类:" + clazzProxy.getSuperclass().getName()); 
[java] view plaincopyprint?
  1. System.out.println("代理类" + clazzProxy.getName() + "的父类:" + clazzProxy.getSuperclass().getName());  
代理类$Proxy0的父类:java.lang.reflect.Proxy
[java] view plaincopyprint?
  1. Class[] clazzInterfaces = clazzProxy.getInterfaces(); 
  2. StringBuilder sbInterfaces = new StringBuilder(); 
  3. for (Class clazzInterface : clazzInterfaces) { 
  4.     sbInterfaces.append(clazzInterface.getName()).append(","); 
  5. sbInterfaces.deleteCharAt(sbInterfaces.length()-1); 
  6. System.out.println("代理类" + clazzProxy.getName() + "所实现的接口:" + sbInterfaces); 
[java] view plaincopyprint?
  1. Class[] clazzInterfaces = clazzProxy.getInterfaces();  
  2. StringBuilder sbInterfaces = new StringBuilder();  
  3. for (Class clazzInterface : clazzInterfaces) {  
  4.     sbInterfaces.append(clazzInterface.getName()).append(",");  
  5. }  
  6. sbInterfaces.deleteCharAt(sbInterfaces.length()-1);  
  7. System.out.println("代理类" + clazzProxy.getName() + "所实现的接口:" + sbInterfaces);  
代理类$Proxy0所实现的接口:java.util.List,java.util.RandomAccess,java.lang.Cloneable,java.io.Serializable
[java] view plaincopyprint?
  1. System.out.println("代理类" + clazzProxy.getName() + "的访问修饰符:" + clazzProxy.getModifiers()); 
[java] view plaincopyprint?
  1. System.out.println("代理类" + clazzProxy.getName() + "的访问修饰符:" + clazzProxy.getModifiers());  
代理类$Proxy0的访问修饰符:17
由访问修饰符的值可得知代理类的修饰符为:代理类的访问修饰符为:public final,由clazzProxy.getModifiers();得知为17,其中public代表1,final代表16,相加得17。参考java.lang.reflect.Modifier
[java] view plaincopyprint?
  1. System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的构造方法列表-------------"); 
  2. Constructor[] constructors = clazzProxy.getConstructors(); 
  3. for (Constructor constructor : constructors) { 
  4. System.out.println("访问修饰符:" + constructor.getModifiers()); 
  5. String name = constructor.getName(); 
  6.     int modifiers = constructor.getModifiers(); 
  7.     StringBuilder sb = new StringBuilder(name); 
  8.     sb.append('('); 
  9.     Class[] clazzParameters = constructor.getParameterTypes(); 
  10.     for (Class clazzParameter : clazzParameters) { 
  11.         sb.append(clazzParameter.getName()).append(","); 
  12.     } 
  13.     if (clazzParameters != null && clazzParameters.length != 0) { 
  14.         sb.deleteCharAt(sb.length()-1); 
  15.     } 
  16.     sb.append(')'); 
  17.     System.out.println(sb.toString()); 
[java] view plaincopyprint?
  1. System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的构造方法列表-------------");  
  2. Constructor[] constructors = clazzProxy.getConstructors();  
  3. for (Constructor constructor : constructors) {  
  4. System.out.println("访问修饰符:" + constructor.getModifiers());  
  5. String name = constructor.getName();  
  6.     int modifiers = constructor.getModifiers();  
  7.     StringBuilder sb = new StringBuilder(name);  
  8.     sb.append('(');  
  9.     Class[] clazzParameters = constructor.getParameterTypes();  
  10.     for (Class clazzParameter : clazzParameters) {  
  11.         sb.append(clazzParameter.getName()).append(",");  
  12.     }  
  13.     if (clazzParameters != null && clazzParameters.length != 0) {  
  14.         sb.deleteCharAt(sb.length()-1);  
  15.     }  
  16.     sb.append(')');  
  17.     System.out.println(sb.toString());  
  18. }  
-------------打印代理类$Proxy0的构造方法列表-------------
访问修饰符:1
$Proxy0(java.lang.reflect.InvocationHandler)
[java] view plaincopyprint?
  1. System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的方法列表-------------"); 
  2. Method[] methods = clazzProxy.getMethods(); 
  3. for (Method method : methods) { 
  4.     String name = method.getName(); 
  5.     StringBuilder sb = new StringBuilder(name); 
  6.     sb.append('('); 
  7.     Class[] clazzParameters = method.getParameterTypes(); 
  8.     for (Class clazzParameter : clazzParameters) { 
  9.         sb.append(clazzParameter.getName()).append(","); 
  10.     } 
  11.     if (clazzParameters != null && clazzParameters.length != 0) { 
  12.         sb.deleteCharAt(sb.length()-1); 
  13.     } 
  14.     sb.append(')'); 
  15.     System.out.println(sb.toString()); 
[java] view plaincopyprint?
  1. System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的方法列表-------------");  
  2. Method[] methods = clazzProxy.getMethods();  
  3. for (Method method : methods) {  
  4.     String name = method.getName();  
  5.     StringBuilder sb = new StringBuilder(name);  
  6.     sb.append('(');  
  7.     Class[] clazzParameters = method.getParameterTypes();  
  8.     for (Class clazzParameter : clazzParameters) {  
  9.         sb.append(clazzParameter.getName()).append(",");  
  10.     }  
  11.     if (clazzParameters != null && clazzParameters.length != 0) {  
  12.         sb.deleteCharAt(sb.length()-1);  
  13.     }  
  14.     sb.append(')');  
  15.     System.out.println(sb.toString());  
  16. }  
打印结果:
[java] view plaincopyprint?
  1. -------------打印代理类$Proxy0的方法列表------------- 
  2. add(java.lang.Object) 
  3. add(int,java.lang.Object) 
  4. get(int
  5. equals(java.lang.Object) 
  6. toString() 
  7. hashCode() 
  8. indexOf(java.lang.Object) 
  9. clear() 
  10. contains(java.lang.Object) 
  11. isEmpty() 
  12. lastIndexOf(java.lang.Object) 
  13. addAll(java.util.Collection) 
  14. addAll(int,java.util.Collection) 
  15. iterator() 
  16. size() 
  17. toArray() 
  18. toArray([Ljava.lang.Object;) 
  19. remove(java.lang.Object) 
  20. remove(int
  21. set(int,java.lang.Object) 
  22. containsAll(java.util.Collection) 
  23. removeAll(java.util.Collection) 
  24. retainAll(java.util.Collection) 
  25. subList(int,int
  26. listIterator() 
  27. listIterator(int
  28. isProxyClass(java.lang.Class) 
  29. getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;) 
  30. getInvocationHandler(java.lang.Object) 
  31. newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler) 
  32. wait(long
  33. wait() 
  34. wait(long,int
  35. getClass() 
  36. notify() 
  37. notifyAll() 
[java] view plaincopyprint?
  1. -------------打印代理类$Proxy0的方法列表-------------  
  2. add(java.lang.Object)  
  3. add(int,java.lang.Object)  
  4. get(int)  
  5. equals(java.lang.Object)  
  6. toString()  
  7. hashCode()  
  8. indexOf(java.lang.Object)  
  9. clear()  
  10. contains(java.lang.Object)  
  11. isEmpty()  
  12. lastIndexOf(java.lang.Object)  
  13. addAll(java.util.Collection)  
  14. addAll(int,java.util.Collection)  
  15. iterator()  
  16. size()  
  17. toArray()  
  18. toArray([Ljava.lang.Object;)  
  19. remove(java.lang.Object)  
  20. remove(int)  
  21. set(int,java.lang.Object)  
  22. containsAll(java.util.Collection)  
  23. removeAll(java.util.Collection)  
  24. retainAll(java.util.Collection)  
  25. subList(int,int)  
  26. listIterator()  
  27. listIterator(int)  
  28. isProxyClass(java.lang.Class)  
  29. getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)  
  30. getInvocationHandler(java.lang.Object)  
  31. newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)  
  32. wait(long)  
  33. wait()  
  34. wait(long,int)  
  35. getClass()  
  36. notify()  
  37. notifyAll()  
这些方法分别来自List接口、Proxy和Object类,因为代理类会自动实现目标类相同的接口。
[java] view plaincopyprint?
  1. //由上述信息可推断出代理类的文件结构(程序中只实现打印代理类的声明部份) 
  2. StringBuilder sbProxyClassStruct = new StringBuilder("public final class "); 
  3. sbProxyClassStruct.append(clazzProxy.getName()) 
  4.           .append(" extends ").append(clazzProxy.getSuperclass().getName()) 
  5.           .append(" implements ").append(sbInterfaces).append(" { } "); 
  6. System.out.println("代理类的结构:" + sbProxyClassStruct); 
[java] view plaincopyprint?
  1. //由上述信息可推断出代理类的文件结构(程序中只实现打印代理类的声明部份)  
  2. StringBuilder sbProxyClassStruct = new StringBuilder("public final class ");  
  3. sbProxyClassStruct.append(clazzProxy.getName())  
  4.           .append(" extends ").append(clazzProxy.getSuperclass().getName())  
  5.           .append(" implements ").append(sbInterfaces).append(" { } ");  
  6. System.out.println("代理类的结构:" + sbProxyClassStruct);  
程序中只打印了代理类的声明部份,结果:
代理类声明部份的结构:public final class $Proxy0 extends java.lang.reflect.Proxy implements java.util.List,java.util.RandomAccess,java.lang.Cloneable,java.io.Serializable { } 

由上述信息可推断出代理类的文件结构:
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. import java.lang.reflect.InvocationHandler; 
  4. import java.util.Collection; 
  5. import java.util.Iterator; 
  6. import java.util.List; 
  7. import java.util.ListIterator; 
  8.  
  9. public final class $Proxy0 extends java.lang.reflect.Proxy implements java.util.List, 
  10.         java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable { 
  11.  
  12.     public $Proxy0(InvocationHandler h) { 
  13.         super(h); 
  14.         // TODO Auto-generated constructor stub 
  15.     } 
  16.  
  17.     @Override 
  18.     public boolean add(Object e) { 
  19.         // TODO Auto-generated method stub 
  20.         return false
  21.     } 
  22.  
  23.     @Override 
  24.     public void add(int index, Object element) { 
  25.         // TODO Auto-generated method stub 
  26.          
  27.     } 
  28.  
  29.     @Override 
  30.     public boolean addAll(Collection c) { 
  31.         // TODO Auto-generated method stub 
  32.         return false
  33.     } 
  34.  
  35.     @Override 
  36.     public boolean addAll(int index, Collection c) { 
  37.         // TODO Auto-generated method stub 
  38.         return false
  39.     } 
  40.  
  41.     @Override 
  42.     public void clear() { 
  43.         // TODO Auto-generated method stub 
  44.          
  45.     } 
  46.  
  47.     @Override 
  48.     public boolean contains(Object o) { 
  49.         // TODO Auto-generated method stub 
  50.         return false
  51.     } 
  52.  
  53.     @Override 
  54.     public boolean containsAll(Collection c) { 
  55.         // TODO Auto-generated method stub 
  56.         return false
  57.     } 
  58.  
  59.     @Override 
  60.     public Object get(int index) { 
  61.         // TODO Auto-generated method stub 
  62.         return null
  63.     } 
  64.  
  65.     @Override 
  66.     public int indexOf(Object o) { 
  67.         // TODO Auto-generated method stub 
  68.         return 0
  69.     } 
  70.  
  71.     @Override 
  72.     public boolean isEmpty() { 
  73.         // TODO Auto-generated method stub 
  74.         return false
  75.     } 
  76.  
  77.     @Override 
  78.     public Iterator iterator() { 
  79.         // TODO Auto-generated method stub 
  80.         return null
  81.     } 
  82.  
  83.     @Override 
  84.     public int lastIndexOf(Object o) { 
  85.         // TODO Auto-generated method stub 
  86.         return 0
  87.     } 
  88.  
  89.     @Override 
  90.     public ListIterator listIterator() { 
  91.         // TODO Auto-generated method stub 
  92.         return null
  93.     } 
  94.  
  95.     @Override 
  96.     public ListIterator listIterator(int index) { 
  97.         // TODO Auto-generated method stub 
  98.         return null
  99.     } 
  100.  
  101.     @Override 
  102.     public boolean remove(Object o) { 
  103.         // TODO Auto-generated method stub 
  104.         return false
  105.     } 
  106.  
  107.     @Override 
  108.     public Object remove(int index) { 
  109.         // TODO Auto-generated method stub 
  110.         return null
  111.     } 
  112.  
  113.     @Override 
  114.     public boolean removeAll(Collection c) { 
  115.         // TODO Auto-generated method stub 
  116.         return false
  117.     } 
  118.  
  119.     @Override 
  120.     public boolean retainAll(Collection c) { 
  121.         // TODO Auto-generated method stub 
  122.         return false
  123.     } 
  124.  
  125.     @Override 
  126.     public Object set(int index, Object element) { 
  127.         // TODO Auto-generated method stub 
  128.         return null
  129.     } 
  130.  
  131.     @Override 
  132.     public int size() { 
  133.         // TODO Auto-generated method stub 
  134.         return 0
  135.     } 
  136.  
  137.     @Override 
  138.     public List subList(int fromIndex, int toIndex) { 
  139.         // TODO Auto-generated method stub 
  140.         return null
  141.     } 
  142.  
  143.     @Override 
  144.     public Object[] toArray() { 
  145.         // TODO Auto-generated method stub 
  146.         return null
  147.     } 
  148.  
  149.     @Override 
  150.     public Object[] toArray(Object[] a) { 
  151.         // TODO Auto-generated method stub 
  152.         return null
  153.     } 
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.util.Collection;  
  5. import java.util.Iterator;  
  6. import java.util.List;  
  7. import java.util.ListIterator;  
  8.   
  9. public final class $Proxy0 extends java.lang.reflect.Proxy implements java.util.List,  
  10.         java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {  
  11.   
  12.     public $Proxy0(InvocationHandler h) {  
  13.         super(h);  
  14.         // TODO Auto-generated constructor stub  
  15.     }  
  16.   
  17.     @Override  
  18.     public boolean add(Object e) {  
  19.         // TODO Auto-generated method stub  
  20.         return false;  
  21.     }  
  22.   
  23.     @Override  
  24.     public void add(int index, Object element) {  
  25.         // TODO Auto-generated method stub  
  26.           
  27.     }  
  28.   
  29.     @Override  
  30.     public boolean addAll(Collection c) {  
  31.         // TODO Auto-generated method stub  
  32.         return false;  
  33.     }  
  34.   
  35.     @Override  
  36.     public boolean addAll(int index, Collection c) {  
  37.         // TODO Auto-generated method stub  
  38.         return false;  
  39.     }  
  40.   
  41.     @Override  
  42.     public void clear() {  
  43.         // TODO Auto-generated method stub  
  44.           
  45.     }  
  46.   
  47.     @Override  
  48.     public boolean contains(Object o) {  
  49.         // TODO Auto-generated method stub  
  50.         return false;  
  51.     }  
  52.   
  53.     @Override  
  54.     public boolean containsAll(Collection c) {  
  55.         // TODO Auto-generated method stub  
  56.         return false;  
  57.     }  
  58.   
  59.     @Override  
  60.     public Object get(int index) {  
  61.         // TODO Auto-generated method stub  
  62.         return null;  
  63.     }  
  64.   
  65.     @Override  
  66.     public int indexOf(Object o) {  
  67.         // TODO Auto-generated method stub  
  68.         return 0;  
  69.     }  
  70.   
  71.     @Override  
  72.     public boolean isEmpty() {  
  73.         // TODO Auto-generated method stub  
  74.         return false;  
  75.     }  
  76.   
  77.     @Override  
  78.     public Iterator iterator() {  
  79.         // TODO Auto-generated method stub  
  80.         return null;  
  81.     }  
  82.   
  83.     @Override  
  84.     public int lastIndexOf(Object o) {  
  85.         // TODO Auto-generated method stub  
  86.         return 0;  
  87.     }  
  88.   
  89.     @Override  
  90.     public ListIterator listIterator() {  
  91.         // TODO Auto-generated method stub  
  92.         return null;  
  93.     }  
  94.   
  95.     @Override  
  96.     public ListIterator listIterator(int index) {  
  97.         // TODO Auto-generated method stub  
  98.         return null;  
  99.     }  
  100.   
  101.     @Override  
  102.     public boolean remove(Object o) {  
  103.         // TODO Auto-generated method stub  
  104.         return false;  
  105.     }  
  106.   
  107.     @Override  
  108.     public Object remove(int index) {  
  109.         // TODO Auto-generated method stub  
  110.         return null;  
  111.     }  
  112.   
  113.     @Override  
  114.     public boolean removeAll(Collection c) {  
  115.         // TODO Auto-generated method stub  
  116.         return false;  
  117.     }  
  118.   
  119.     @Override  
  120.     public boolean retainAll(Collection c) {  
  121.         // TODO Auto-generated method stub  
  122.         return false;  
  123.     }  
  124.   
  125.     @Override  
  126.     public Object set(int index, Object element) {  
  127.         // TODO Auto-generated method stub  
  128.         return null;  
  129.     }  
  130.   
  131.     @Override  
  132.     public int size() {  
  133.         // TODO Auto-generated method stub  
  134.         return 0;  
  135.     }  
  136.   
  137.     @Override  
  138.     public List subList(int fromIndex, int toIndex) {  
  139.         // TODO Auto-generated method stub  
  140.         return null;  
  141.     }  
  142.   
  143.     @Override  
  144.     public Object[] toArray() {  
  145.         // TODO Auto-generated method stub  
  146.         return null;  
  147.     }  
  148.   
  149.     @Override  
  150.     public Object[] toArray(Object[] a) {  
  151.         // TODO Auto-generated method stub  
  152.         return null;  
  153.     }  
  154. }  
由上述信息得知该代理类只有一个带InvocationHandler参数的构造方法,现在我们来生成这个代理类的实例对象:
[java] view plaincopyprint?
  1. //方式1,创建一个内部类,并实现InvocationHandler接口 
  2. Constructor proxy1 = clazzProxy.getConstructor(InvocationHandler.class); 
  3. System.out.println("------------创建代理类实例,方式1--------------------"); 
  4. class MyInvocationHandler implements InvocationHandler { 
  5.     ArrayList target = new ArrayList(); 
  6.     @Override 
  7.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  8.         String name = method.getName(); 
  9.         System.out.println(name + "方法调用前..."); 
  10.         Object retVal = method.invoke(target, args); 
  11.         System.out.println(name + "方法调用后的返回结果为:" + retVal); 
  12.         System.out.println(name + "方法调用后...\n"); 
  13.         return retVal; 
  14.     } 
  15.              
  16. List list1 = (List)proxy1.newInstance(new MyInvocationHandler()); 
  17. list1.add("zhangsan"); 
  18. list1.add("lisi"); 
  19. System.out.println(list1.size()); 
[java] view plaincopyprint?
  1. //方式1,创建一个内部类,并实现InvocationHandler接口  
  2. Constructor proxy1 = clazzProxy.getConstructor(InvocationHandler.class);  
  3. System.out.println("------------创建代理类实例,方式1--------------------");  
  4. class MyInvocationHandler implements InvocationHandler {  
  5.     ArrayList target = new ArrayList();  
  6.     @Override  
  7.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  8.         String name = method.getName();  
  9.         System.out.println(name + "方法调用前...");  
  10.         Object retVal = method.invoke(target, args);  
  11.         System.out.println(name + "方法调用后的返回结果为:" + retVal);  
  12.         System.out.println(name + "方法调用后...\n");  
  13.         return retVal;  
  14.     }  
  15.               
  16. }  
  17. List list1 = (List)proxy1.newInstance(new MyInvocationHandler());  
  18. list1.add("zhangsan");  
  19. list1.add("lisi");  
  20. System.out.println(list1.size());  
调用List接口的add方法和size方法后的输出结果:
---------------------创建代理类$Proxy0的实例对象----------------------
------------创建代理类实例,方式1--------------------
add方法调用前...
add方法调用后的返回结果为:true
add方法调用后...

add方法调用前...
add方法调用后的返回结果为:true
add方法调用后...

size方法调用前...
size方法调用后的返回结果为:2
size方法调用后...
2
[java] view plaincopyprint?
  1. //方式2 
  2. Constructor prox2 = clazzProxy.getConstructor(InvocationHandler.class); 
  3. List list2 = (List)prox2.newInstance(new InvocationHandler() { 
  4.     List target = new ArrayList(); 
  5.     @Override 
  6.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  7.         Object retVal = method.invoke(target, args); 
  8.         return retVal; 
  9.     }} 
  10. ); 
[java] view plaincopyprint?
  1. //方式2  
  2. Constructor prox2 = clazzProxy.getConstructor(InvocationHandler.class);  
  3. List list2 = (List)prox2.newInstance(new InvocationHandler() {  
  4.     List target = new ArrayList();  
  5.     @Override  
  6.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  7.         Object retVal = method.invoke(target, args);  
  8.         return retVal;  
  9.     }}  
  10. );  
[java] view plaincopyprint?
  1. //方式3(匿名类),将创建代理类和创建代理类实例对象的步聚合二为一 
  2. System.out.println("------------创建代理类实例,方式3--------------------"); 
  3. List list3 = (List)Proxy.newProxyInstance( 
  4.     ArrayList.class.getClassLoader(),  
  5.     ArrayList.class.getInterfaces(), 
  6.         new InvocationHandler() { 
  7.             ArrayList target = new ArrayList(); 
  8.             @Override 
  9.             public Object invoke(Object proxy, Method method, 
  10.                     Object[] args) throws Throwable { 
  11.                 //测试方法的运行效率 
  12.                 long beginTime = System.currentTimeMillis(); 
  13.                 Object retVal = method.invoke(target, args); 
  14.                 long endTime = System.currentTimeMillis(); 
  15.                 System.out.println(method.getName() + " 方法运行时长为:" + (endTime - beginTime)); 
  16.                 return retVal; 
  17.             }} 
  18.         ); 
  19.         list3.add("hy"); 
  20.         list3.add("yangxin"); 
  21.         System.out.println(list3.size()); 
[java] view plaincopyprint?
  1. //方式3(匿名类),将创建代理类和创建代理类实例对象的步聚合二为一  
  2. System.out.println("------------创建代理类实例,方式3--------------------");  
  3. List list3 = (List)Proxy.newProxyInstance(  
  4.     ArrayList.class.getClassLoader(),   
  5.     ArrayList.class.getInterfaces(),  
  6.         new InvocationHandler() {  
  7.             ArrayList target = new ArrayList();  
  8.             @Override  
  9.             public Object invoke(Object proxy, Method method,  
  10.                     Object[] args) throws Throwable {  
  11.                 //测试方法的运行效率  
  12.                 long beginTime = System.currentTimeMillis();  
  13.                 Object retVal = method.invoke(target, args);  
  14.                 long endTime = System.currentTimeMillis();  
  15.                 System.out.println(method.getName() + " 方法运行时长为:" + (endTime - beginTime));  
  16.                 return retVal;  
  17.             }}  
  18.         );  
  19.         list3.add("hy");  
  20.         list3.add("yangxin");  
  21.         System.out.println(list3.size());  
输出结果:
------------创建代理类实例,方式3--------------------
add 方法运行时长为:0
add 方法运行时长为:0
size 方法运行时长为:0
2

*通过以上代码的分析,可将生成代理类的代码,抽取成一个生成代理的通用方法,并将功能代码用一个对象封装起来(如:测试方法的运行时间,方法运行前或运行后需要做的事情)
[java] view plaincopyprint?
  1. /**
  2. * 获得代理对象
  3. * @param target 目标(被代理的对象)
  4. * @param advice 目标对象中的方法被调用前要执行的功能
  5. * @return 目标的代理对象
  6. */ 
  7. private static Object getProxy(final Object target,final Advice advice) { 
  8.     return Proxy.newProxyInstance( 
  9.             target.getClass().getClassLoader(),  
  10.             target.getClass().getInterfaces(), 
  11.             new InvocationHandler() { 
  12.                 @Override 
  13.                 public Object invoke(Object proxy, Method method, 
  14.                         Object[] args) throws Throwable { 
  15.                     Object retVal = null
  16.                     try { 
  17.                         advice.doBefore(target, method, args);//方法执行前 
  18.                         retVal = method.invoke(target, args); 
  19.                         advice.doAfter(target, method, args, retVal);//方法执行后 
  20.                     } catch (Exception e) { 
  21.                         advice.doThrow(target, method, args, e);//方法抛出异常 
  22.                     } finally { 
  23.                         advice.doFinally(target, method, args);//方法最终执行代码(用于释放数据资源、关闭IO流等操作) 
  24.                     } 
  25.                     return retVal; 
  26.                     }} 
  27.                 ); 
  28.     } 
[java] view plaincopyprint?
  1. /** 
  2.  * 获得代理对象 
  3.  * @param target 目标(被代理的对象) 
  4.  * @param advice 目标对象中的方法被调用前要执行的功能 
  5.  * @return 目标的代理对象 
  6. */  
  7. private static Object getProxy(final Object target,final Advice advice) {  
  8.     return Proxy.newProxyInstance(  
  9.             target.getClass().getClassLoader(),   
  10.             target.getClass().getInterfaces(),  
  11.             new InvocationHandler() {  
  12.                 @Override  
  13.                 public Object invoke(Object proxy, Method method,  
  14.                         Object[] args) throws Throwable {  
  15.                     Object retVal = null;  
  16.                     try {  
  17.                         advice.doBefore(target, method, args);//方法执行前  
  18.                         retVal = method.invoke(target, args);  
  19.                         advice.doAfter(target, method, args, retVal);//方法执行后  
  20.                     } catch (Exception e) {  
  21.                         advice.doThrow(target, method, args, e);//方法抛出异常  
  22.                     } finally {  
  23.                         advice.doFinally(target, method, args);//方法最终执行代码(用于释放数据资源、关闭IO流等操作)  
  24.                     }  
  25.                     return retVal;  
  26.                     }}  
  27.                 );  
  28.     }  
封装功能的对象:
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. import java.lang.reflect.Method; 
  4.  
  5. /**
  6. * aop接口,提供方法运行前、方法运行后、方法运行中产生Exception、方法最终运行代码
  7. *
  8. */ 
  9. public interface Advice { 
  10.      
  11.     /**
  12.      * 方法运行前
  13.      * @param target 被代理的目标对象
  14.      * @param method 被调用的方法
  15.      * @param args 方法的参数
  16.      */ 
  17.     public void doBefore(Object target, Method method, Object[] args); 
  18.      
  19.     /**
  20.      * 方法运行后
  21.      * @param target 被代理的目标对象
  22.      * @param method 被调用的方法对象
  23.      * @param args 方法的参数
  24.      * @param retVal 方法的返回值
  25.      */ 
  26.     public void doAfter(Object target, Method method, Object[] args, Object retVal); 
  27.      
  28.     /**
  29.      * 方法运行时产生的异常
  30.      * @param target 被代理的目标对象
  31.      * @param method 被调用的方法
  32.      * @param args 方法参数
  33.      * @param e 运行时的异常对象
  34.      */ 
  35.     public void doThrow(Object target, Method method, Object[] args, Exception e); 
  36.      
  37.     /**
  38.      * 最终要执行的功能(如释放数据库连接的资源、关闭IO流等)
  39.      * @param target 被代理的目标对象
  40.      * @param method 被调用的方法
  41.      * @param args 方法参数
  42.      */ 
  43.     public void doFinally(Object target, Method method, Object[] args); 
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. /** 
  6.  * aop接口,提供方法运行前、方法运行后、方法运行中产生Exception、方法最终运行代码 
  7.  * 
  8.  */  
  9. public interface Advice {  
  10.       
  11.     /** 
  12.      * 方法运行前 
  13.      * @param target 被代理的目标对象 
  14.      * @param method 被调用的方法 
  15.      * @param args 方法的参数 
  16.      */  
  17.     public void doBefore(Object target, Method method, Object[] args);  
  18.       
  19.     /** 
  20.      * 方法运行后 
  21.      * @param target 被代理的目标对象 
  22.      * @param method 被调用的方法对象 
  23.      * @param args 方法的参数 
  24.      * @param retVal 方法的返回值 
  25.      */  
  26.     public void doAfter(Object target, Method method, Object[] args, Object retVal);  
  27.       
  28.     /** 
  29.      * 方法运行时产生的异常 
  30.      * @param target 被代理的目标对象 
  31.      * @param method 被调用的方法 
  32.      * @param args 方法参数 
  33.      * @param e 运行时的异常对象 
  34.      */  
  35.     public void doThrow(Object target, Method method, Object[] args, Exception e);  
  36.       
  37.     /** 
  38.      * 最终要执行的功能(如释放数据库连接的资源、关闭IO流等) 
  39.      * @param target 被代理的目标对象 
  40.      * @param method 被调用的方法 
  41.      * @param args 方法参数 
  42.      */  
  43.     public void doFinally(Object target, Method method, Object[] args);  
  44. }  
再建一个日志功能的实现类LogAdvice,用于测试:
[java] view plaincopyprint?
  1. package proxy; 
  2.  
  3. import java.lang.reflect.Method; 
  4. import java.util.Arrays; 
  5.  
  6. /**
  7. * 日志功能切入类
  8. * @author 杨信
  9. *
  10. */ 
  11. public class LogAdvice implements Advice { 
  12.  
  13.     long beginTime = System.currentTimeMillis(); 
  14.      
  15.     @Override 
  16.     public void doBefore(Object target, Method method, Object[] args) { 
  17.         System.out.println(target.getClass().getSimpleName() + 
  18.                 "." + method.getName() + "方法被调用,参数值:" + Arrays.toString(args)); 
  19.  
  20.     } 
  21.      
  22.     @Override 
  23.     public void doAfter(Object target, Method method, Object[] args, Object retVal) { 
  24.         long endTime = System.currentTimeMillis(); 
  25.         System.out.println(target.getClass().getSimpleName() + 
  26.                 "." + method.getName() + "方法运行结束,返回值:" + retVal + ",耗时" + (endTime - beginTime) + "毫秒。"); 
  27.  
  28.     } 
  29.  
  30.     @Override 
  31.     public void doThrow(Object target, Method method, Object[] args, 
  32.             Exception e) { 
  33.         System.out.println("调用" + target.getClass().getSimpleName() + 
  34.                 "." + method.getName() + "方法发生异常,异常消息:"); 
  35.         e.printStackTrace(); 
  36.     } 
  37.  
  38.     @Override 
  39.     public void doFinally(Object target, Method method, Object[] args) { 
  40.         System.out.println("doFinally..."); 
  41.          
  42.     } 
  43.  
[java] view plaincopyprint?
  1. package proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4. import java.util.Arrays;  
  5.   
  6. /** 
  7.  * 日志功能切入类 
  8.  * @author 杨信 
  9.  * 
  10.  */  
  11. public class LogAdvice implements Advice {  
  12.   
  13.     long beginTime = System.currentTimeMillis();  
  14.       
  15.     @Override  
  16.     public void doBefore(Object target, Method method, Object[] args) {  
  17.         System.out.println(target.getClass().getSimpleName() +  
  18.                 "." + method.getName() + "方法被调用,参数值:" + Arrays.toString(args));  
  19.   
  20.     }  
  21.       
  22.     @Override  
  23.     public void doAfter(Object target, Method method, Object[] args, Object retVal) {  
  24.         long endTime = System.currentTimeMillis();  
  25.         System.out.println(target.getClass().getSimpleName() +  
  26.                 "." + method.getName() + "方法运行结束,返回值:" + retVal + ",耗时" + (endTime - beginTime) + "毫秒。");  
  27.   
  28.     }  
  29.   
  30.     @Override  
  31.     public void doThrow(Object target, Method method, Object[] args,  
  32.             Exception e) {  
  33.         System.out.println("调用" + target.getClass().getSimpleName() +  
  34.                 "." + method.getName() + "方法发生异常,异常消息:");  
  35.         e.printStackTrace();  
  36.     }  
  37.   
  38.     @Override  
  39.     public void doFinally(Object target, Method method, Object[] args) {  
  40.         System.out.println("doFinally...");  
  41.           
  42.     }  
  43.   
  44. }  
测试生成代理的通用方法:
[java] view plaincopyprint?
  1. ArrayList target = new ArrayList(); 
  2. List list4 = (List)getProxy(target,new LogAdvice()); 
  3. list4.add("张三"); 
  4. list4.add("李四"); 
  5. list4.add("王五"); 
  6. System.out.println(list4.size()); 
  7. list4.get(3);   //演示异常advice 
[java] view plaincopyprint?
  1. ArrayList target = new ArrayList();  
  2. List list4 = (List)getProxy(target,new LogAdvice());  
  3. list4.add("张三");  
  4. list4.add("李四");  
  5. list4.add("王五");  
  6. System.out.println(list4.size());  
  7. list4.get(3);   //演示异常advice  
输出结果:
[java] view plaincopyprint?
  1. ArrayList.add方法被调用,参数值:[张三] 
  2. ArrayList.add方法运行结束,返回值:true,耗时0毫秒。 
  3. doFinally... 
  4. ArrayList.add方法被调用,参数值:[李四] 
  5. ArrayList.add方法运行结束,返回值:true,耗时0毫秒。 
  6. doFinally... 
  7. ArrayList.add方法被调用,参数值:[王五] 
  8. ArrayList.add方法运行结束,返回值:true,耗时0毫秒。 
  9. doFinally... 
  10. ArrayList.size方法被调用,参数值:null 
  11. ArrayList.size方法运行结束,返回值:3,耗时0毫秒。 
  12. doFinally... 
  13. 3 
  14. ArrayList.get方法被调用,参数值:[3
  15. 调用ArrayList.get方法发生异常,异常消息: 
  16. java.lang.reflect.InvocationTargetException 
  17.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
  18.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39
  19.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25
  20.     at java.lang.reflect.Method.invoke(Method.java:597
  21.     at proxy.DynamicProxyTest$3.invoke(DynamicProxyTest.java:163
  22.     at $Proxy0.get(Unknown Source) 
  23.     at proxy.DynamicProxyTest.main(DynamicProxyTest.java:143
  24. Caused by: java.lang.IndexOutOfBoundsException: Index: 3, Size: 3 
  25.     at java.util.ArrayList.RangeCheck(ArrayList.java:547
  26.     at java.util.ArrayList.get(ArrayList.java:322
  27.     ... 7 more 
  28. doFinally... 
[java] view plaincopyprint?
  1. ArrayList.add方法被调用,参数值:[张三]  
  2. ArrayList.add方法运行结束,返回值:true,耗时0毫秒。  
  3. doFinally...  
  4. ArrayList.add方法被调用,参数值:[李四]  
  5. ArrayList.add方法运行结束,返回值:true,耗时0毫秒。  
  6. doFinally...  
  7. ArrayList.add方法被调用,参数值:[王五]  
  8. ArrayList.add方法运行结束,返回值:true,耗时0毫秒。  
  9. doFinally...  
  10. ArrayList.size方法被调用,参数值:null  
  11. ArrayList.size方法运行结束,返回值:3,耗时0毫秒。  
  12. doFinally...  
  13. 3  
  14. ArrayList.get方法被调用,参数值:[3]  
  15. 调用ArrayList.get方法发生异常,异常消息:  
  16. java.lang.reflect.InvocationTargetException  
  17.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
  18.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
  19.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
  20.     at java.lang.reflect.Method.invoke(Method.java:597)  
  21.     at proxy.DynamicProxyTest$3.invoke(DynamicProxyTest.java:163)  
  22.     at $Proxy0.get(Unknown Source)  
  23.     at proxy.DynamicProxyTest.main(DynamicProxyTest.java:143)  
  24. Caused by: java.lang.IndexOutOfBoundsException: Index: 3, Size: 3  
  25.     at java.util.ArrayList.RangeCheck(ArrayList.java:547)  
  26.     at java.util.ArrayList.get(ArrayList.java:322)  
  27.     ... 7 more  
  28. doFinally...  
完毕,通过动态代理机制,实现了传说中的AOP思想。
0 0
原创粉丝点击