java代理

java中的代理按照代理类的生成时期不同分为静态代理和动态代理。

1)静态代理。由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。下面是静态代理的UML图。

 
java代理_第1张图片

具体的代码如下

Java代码    收藏代码
  1. 1.  interface Subject    
  2. 2.  {    
  3. 3.      void request();    
  4. 4.  }    
  5. 5.  class RealSubject implements Subject    
  6. 6.  {    
  7. 7.      public void request()    
  8. 8.      {    
  9. 9.          System.out.println("真实的请求");    
  10. 10.     }    
  11. 11. }    
  12. 12public class Proxy implements Subject    
  13. 13. {    
  14. 14.     RealSubject realSubject;    
  15. 15.     public void request()    
  16. 16.     {    
  17. 17.         if(realSubject==null)    
  18. 18.         {    
  19. 19.             realSubject=new RealSubject();    
  20. 20.         }    
  21. 21.         realSubject.request();    
  22. 22.     }    
  23. 23.         
  24. 24.     public static void main(String[] args) {    
  25. 25.         new Proxy().request();    
  26. 26.     }    
  27. 27. }    

 

2动态代理。动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性。想必做java web开发的,会经常用到Spring,而Spring2大核心之一是Spring AOP,Spring AOP就是利用动态代理实的(Spring利用动态代理技术实现的最重要的一个功能就是声明式事务)。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。那么接下来就利用动态代理实现上面的例子

Java代码    收藏代码
  1. 1.  import java.lang.reflect.InvocationHandler;    
  2. 2.  import java.lang.reflect.Method;    
  3. 3.  import java.lang.reflect.Proxy;    
  4. 4.      
  5. 5.  interface Subject {    
  6. 6.      void request();    
  7. 7.  }    
  8. 8.      
  9. 9.  class RealSubject implements Subject {    
  10. 10.     public void request() {    
  11. 11.         System.out.println("真实的请求");    
  12. 12.     }    
  13. 13. }    
  14. 14.     
  15. 15public class DynProxy implements InvocationHandler {    
  16. 16.     
  17. 17.     private Object dele;    
  18. 18.     
  19. 19.     public DynProxy(Object obj) {    
  20. 20.         this.dele = obj;    
  21. 21.     }    
  22. 22.     
  23. 23.     public Object invoke(Object proxy, Method method, Object[] args)    
  24. 24.             throws Throwable {    
  25. 25.         doBefore();    
  26. 26.         // 在这里完全可以把下面这句注释掉,而做一些其它的事情    
  27. 27.         Object result = method.invoke(dele, args);    
  28. 28.         after();    
  29. 29.         return result;    
  30. 30.     }    
  31. 31.     
  32. 32.     private void doBefore() {    
  33. 33.         System.out.println("before....");    
  34. 34.     }    
  35. 35.     
  36. 36.     private void after() {    
  37. 37.         System.out.println("after....");    
  38. 38.     }    
  39. 39.     
  40. 40.     public static void main(String[] args) {    
  41. 41.         RealSubject realSubject= new RealSubject();    
  42. 42.         DynProxy dynProxy= new DynProxy(realSubject);    
  43. 43.         Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), dynProxy);    
  44. 44.         subject.request();    
  45. 45.     }    
  46. 46. }   

 

这是JDK的动态代理,JDK的自动代理只能对接口实现自动代理,从代码当中也可以看出来realSubject.getClass().getInterfaces().JDK动态对接口进行实现,实现的方法是个空方法,那么动态代理又是怎么调用的realSubject相对应的实现方法呢,答案就是InvocationHandler,它关联了实现类,在上面的例子中也就是realSubject,它会调用realSubject相对应的实现方法。

 

 JDK的动态代理有一个特别明显的不足,即只能对接口实现动态代理。cglibCode Generation Library)的出现则弥补了JDK代理的不足,cglib能够实现对类进行动态代理。下面就用cglib来实现上面的例子。
 

Java代码    收藏代码
  1. 1.  import java.lang.reflect.Method;    
  2. 2.  import net.sf.cglib.proxy.Enhancer;    
  3. 3.  import net.sf.cglib.proxy.MethodInterceptor;    
  4. 4.  import net.sf.cglib.proxy.MethodProxy;    
  5. 5.      
  6. 6.  class RealSubject {    
  7. 7.      public void request() {    
  8. 8.          System.out.println("真实的请求");    
  9. 9.      }    
  10. 10.         private void privateExample(){    
  11. 11.                  System.out.println("这个是私有方法不能被子类继承");    
  12. 12.         }    
  13. 13.             
  14. 14. }    
  15. 15.     
  16. 16public class MyMethodInterceptor implements MethodInterceptor {    
  17. 17.     
  18. 18.     public Object intercept(Object object, Method method, Object[] args,    
  19. 19.             MethodProxy methodProxy) throws Throwable {    
  20. 20.         System.out.println(">>>MethodInterceptor start...");    
  21. 21.         Object result = methodProxy.invokeSuper(object, args);    
  22. 22.         System.out.println(">>>MethodInterceptor ending...");    
  23. 23.         return "hahahh";    
  24. 24.     }    
  25. 25.     
  26. 26.     public Object createProxy(Class targetClass) {    
  27. 27.         Enhancer enhancer = new Enhancer();    
  28. 28.         enhancer.setSuperclass(targetClass);    
  29. 29.         enhancer.setCallback(new MyMethodInterceptor());    
  30. 30.         return enhancer.create();    
  31. 31.     }    
  32. 32.     
  33. 33.     public static void main(String[] args) {    
  34. 34.         RealSubject target = new RealSubject();    
  35. 35.         MyMethodInterceptor test = new MyMethodInterceptor();    
  36. 36.         RealSubject proxyTarget = (RealSubject)test.createProxy(RealSubject.class);    
  37. 37.         proxyTarget.request();    
  38. 38.     }    
  39. 39. }    

 

 cglib能实现对类的动态代理,产生的动态代理类是原始类,在上面的例子就是RealSubject的子类,那么又跑回到了java继承体系当中了,private方法 final方法是不能被子类继承和override的,所以这些方法是不会被动态代理的。像上面的方法privateExample(),就不会出现在main函数中的proxyTarget的方法列表中。

JDK动态代理和cglib动态代理的区别

1JDK动态代理只能对接口实现动态代理,而cglib能对类实现动态代理

2JDK动态代理生成动态代理类的速度或者说效率要比cglib快,但是生成后的动态代理类的效率则是cglib高,一般会高十倍以上,所以如果在Spring中使用动态代理,而Spring中的实例一般都是单例的,所以在Spring中生成动态代理类实例一般选用cglib比较好。这样生成的动态代理类的实例效率高。

闲扯几句:一般类的信息、常量信息会放在jvm内存中的方法区或者说是永久区,如果生成动态代理类过多的话,该区被占用的也就越多,有可能导致该区域的内存溢出(只是有可能,现实当中出现的几率非常小,就顺嘴提一句)。

你可能感兴趣的:(java代理)