zoukankan      html  css  js  c++  java
  • 2017.5.1 java动态代理总结

    参考来自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

    1.代理模式

    1 代理类和委托类有相同接口。
    2 代理类负责为委托类:预处理消息
    3                  过滤消息
    4                  把消息转发给委托类
    5                  事后处理消息等
    6 代理类和委托类会相关联。
    7 代理类不真正实现服务,而是通过调用委托类的相关方法,来提供服务。

    2.代理的分类

    1 静态代理:由程序员创建,或者由特定工具自动生成源代码,再对其编译。在运行之前,代理类的.class文件就存在了。
    2 动态代理:在程序运行时,根据java的反射机制动态创建。
      3 jdk动态代理:委托类必须实现接口
      4
    Cglib动态代理:委托类不用实现接口,针对类

    2.1 静态代理

    (1)实例
    1 public interface Count {  
    2     // 查看账户方法  
    3     public void queryCount();  
    5     // 修改账户方法  
    6     public void updateCount(); 
    8 }  
     1 public class CountImpl implements Count {  
     2   
     3     @Override  
     4     public void queryCount() {  
     5         System.out.println("查看账户方法...");  
     6     }  
     7   
     8     @Override  
     9     public void updateCount() {  
    10         System.out.println("修改账户方法...");  
    12     }  
    13 }  

    创建一个代理类,可以看到CountProxy和CountImpl实现了同样的接口:Count。

     1 public class CountProxy implements Count {  
     2     private CountImpl countImpl;  
     3   
     4     /** 
     5      * 覆盖默认构造器 
     6      *  
     7      * @param countImpl 
     8      */  
     9     public CountProxy(CountImpl countImpl) {  
    10         this.countImpl = countImpl;  
    11     }  
    12   
    13     @Override  
    14     public void queryCount() {  
    15         System.out.println("事务处理之前");  
    16         // 调用委托类的方法;  
    17         countImpl.queryCount();  
    18         System.out.println("事务处理之后");  
    19     }  
    20   
    21     @Override  
    22     public void updateCount() {  
    23         System.out.println("事务处理之前");  
    24         // 调用委托类的方法;  
    25         countImpl.updateCount();  
    26         System.out.println("事务处理之后");  
    27     }  
    28   
    29 }  
    (2)测试

    由测试可知,采用constructor关联起来的proxy和impl,必须是1对1的,十分低效。

    1 public class TestCount {  
    2     public static void main(String[] args) {  
    3         CountImpl countImpl = new CountImpl();  
    4         CountProxy countProxy = new CountProxy(countImpl);  
    5         countProxy.updateCount();  
    6         countProxy.queryCount();  
    7     }  
    8 } 

    显然,通过上面的代码可以知道,这样的代理类只能为一个接口服务,会产生过多的代理类。而且所有的代理类中除了调用的方法不一样,其他操作都一样,重复代码过多。为了使用一个代理类来完成全部的代理功能,显然不能在运行前就生成好代理类的.class文件。即,必须使用动态代理。

    2.2 JDK动态代理

    (1)interface InvocationHandler
    1 public interface InvocationHandler { 
    2      public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
    3 }

    参数说明:

    1 Object proxy:指代理的对象。 
    2 Method method:要调用的方法 
    3 Object[] args:方法调用时所需要的参数 
    (2)class Proxy

    java.lang.reflect.Proxy类提供了一个方法:newProxyInstance。

    1 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  throws IllegalArgumentException 

    参数说明:

    1 ClassLoader loader:类加载器 
    2 Class<?>[] interfaces:得到全部的接口 
    3 InvocationHandler h:得到InvocationHandler接口的子类实例 
    (3)实例
     1 public interface BookFacade {  
     2     public void addBook();  
     3 } 
     4 
     5 public class BookFacadeImpl implements BookFacade {  
     6   
     7     @Override  
     8     public void addBook() {  
     9         System.out.println("增加图书方法。。。");  
    10     }  
    11 }  
     1 import java.lang.reflect.InvocationHandler;  
     2 import java.lang.reflect.Method;  
     3 import java.lang.reflect.Proxy;  
     4   
     5 public class BookFacadeProxy implements InvocationHandler {  
     6     private Object target;  
     7     /** 
     8      * 绑定委托对象并返回一个代理类 
     9      * @param target 委托对象
    10      * @return 代理类
    11      */  
    12     public Object bind(Object target) {  
    13         this.target = target;  
    14         //取得代理对象  //要绑定接口(这是一个缺陷,cglib弥补了) 
    15         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    16   target.getClass().getInterfaces(),
    17         this); 17 } 18 19 @Override 20 /** 21 * 调用委托类的方法 22 */ 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 25 Object result=null; 26 System.out.println("事物开始"); 27 //执行方法 28 result=method.invoke(target, args); 29 System.out.println("事物结束"); 30 return result; 31 } 32 }
    (4)测试

    由测试可知,此时只需要一个代理类,就可以通用了。但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

    1 public class TestProxy {  
    2   
    3     public static void main(String[] args) {  
    4         BookFacadeProxy proxy = new BookFacadeProxy();  
    5         BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
    6         bookProxy.addBook();  
    7     } 
    9 }

    2.3 Cglib动态代理

    由前面可知,当委托类并没有实现某个接口(implements someInterface)时,jdk动态代理就不能使用了。

    cglib是针对类来实现代理(没有实现某个接口也不会造成影响),原理:对委托类生成一个子类(局限:final),并覆盖其中方法实现增强

    (1)实例
    1 public class BookFacadeImpl1 {  //没有implements BookFacade
    2     public void addBook() {  
    3         System.out.println("增加图书的普通方法...");  
    4     }  
    5 } 
     1 import java.lang.reflect.Method;  
     2 
     3 import net.sf.cglib.proxy.Enhancer;  
     4 import net.sf.cglib.proxy.MethodInterceptor;  
     5 import net.sf.cglib.proxy.MethodProxy;  
     6   
     7 public class BookFacadeCglib implements MethodInterceptor {  
     8     private Object target;  
     9   
    10     /** 
    11      * 创建代理对象 13      * @param target 委托类
    14      * @return 代理类
    15      */  
    16     public Object getInstance(Object target) {  
    17         this.target = target;  
    18         Enhancer enhancer = new Enhancer();  
    19         enhancer.setSuperclass(this.target.getClass());  
    20         // 回调方法  
    21         enhancer.setCallback(this);  
    22         // 创建代理对象  
    23         return enhancer.create();  
    24     }  
    25   
    26     @Override  
    27     // 回调方法  
    28     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
    30         System.out.println("事物开始");  
    31         proxy.invokeSuper(obj, args);  
    32         System.out.println("事物结束");  
    33         return null;  
    34     }  
    35   }
    (2)测试
    1 public class TestCglib {  
    2       
    3     public static void main(String[] args) {  
    4         BookFacadeCglib cglib=new BookFacadeCglib();  
    5         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
    6         bookCglib.addBook();  
    7     }  
    8 } 

    3.总结

    1 静态代理缺点:代码一对一,重复冗余,编译时就需要存在代理类的.class文件。
    2 动态代理优点:动态生成,统一处理,运行时生成代理类。
    3 jdk动态代理: Proxy,InvocationHandler
    4 cglib动态代理:MethodInterceptor
  • 相关阅读:
    Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
    MyBatis 实现一对多有几种方式,怎么操作的?
    利用 ps 怎么显示所有的进程? 怎么利用 ps 查看指定进 程的信息?
    哪个命令专门用来查看后台任务?
    什么是 MyBatis 的接口绑定?有哪些实现方式?
    什么是端到端微服务测试?
    我们如何在测试中消除非决定论?
    什么是持续监测?
    怎么使一个命令在后台运行?
    博客园样式美化(兼容为知笔记)
  • 原文地址:https://www.cnblogs.com/lyh421/p/6795898.html
Copyright © 2011-2022 走看看