zoukankan      html  css  js  c++  java
  • 动态代理proxy与CGLib的区别

    1. 什么是代理?
    2. 静态代理与动态代理
    3. 静态代理实例
    4. JDK动态代理实例
    5. CGLib 简介
    6. CGLib 与JDK动态代理的区别

        代理模式是Java中常见的一种模式,英文名字叫走Proxy或者Surrogate,代理的本意是一个人代表另一个人,或者一个机构代表另一个机构,采取行动,因而,代理和现实生活中的中介有很大的类似,你买房子、卖房子,可以自己去操作,但是需要了解和买卖房产无关的细节,如契税等,而找一个中介,则不用关心这些与买卖房产无直接关系的中间细节,只关心业务本身。

         因而,我们可以把代理模式的适用,总结为:代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

       代理模式的用途,可以分为如下几种:

        1)远程代理(Remote ):为远程对象的invoke提供代理,典型的例子如RMI或者EJB,都会在本地生成一个远程对象的stub。

        2)虚拟代理(Virtual):如果需要创建一个资源消耗大的对象,则可以首先使用一个代理,使这个对象在需要时才真正创建。

        3)Copy-On-Write 代理:把复制延迟到客户端需要时才采取行动

        4)保护(Protect)

        5)Cache代理

       2.静态代理与动态代理

    代理分为静态代理和动态代理

       按照代理创建的时期,可以分为动态代理和静态代理:

     静态代理:由程序员或者自动生成工具生成代理类,然后进行代理类的编译和运行。在代理类、委托类运行之前,代理类已经以.class的格式存在。

     静态代理:在程序运行时,由反射机制动态创建而成。

     3.静态代理实例

        静态代理实例:

         首先需要一个接口

    1. package net.battier.dao;  
    2.   
    3. /** 
    4.  * 定义一个账户接口 
    5.  *  
    6.  * @author Administrator 
    7.  *  
    8.  */  
    9. public interface Count {  
    10.     // 查看账户方法  
    11.     public void queryCount();  
    12.   
    13.     // 修改账户方法  
    14.     public void updateCount();  
    15.   
    16. }  

      然后是委托类,也就是接口的真正实现类,内涵主要的业务逻辑:

    1. package net.battier.dao.impl;  
    2.   
    3. import net.battier.dao.Count;  
    4.   
    5. /** 
    6.  * 委托类(包含业务逻辑) 
    7.  *  
    8.  * @author Administrator 
    9.  *  
    10.  */  
    11. public class CountImpl implements Count {  
    12.   
    13.     @Override  
    14.     public void queryCount() {  
    15.         System.out.println("查看账户方法...");  
    16.   
    17.     }  
    18.   
    19.     @Override  
    20.     public void updateCount() {  
    21.         System.out.println("修改账户方法...");  
    22.   
    23.     }  
    24.   
    25. }  

       最后是代理类:

    1. CountProxy.java  
    2. package net.battier.dao.impl;  
    3.   
    4. import net.battier.dao.Count;  
    5.   
    6. /** 
    7.  * 这是一个代理类(增强CountImpl实现类) 
    8.  *  
    9.  * @author Administrator 
    10.  *  
    11.  */  
    12. public class CountProxy implements Count {  
    13.     private CountImpl countImpl;  
    14.   
    15.     /** 
    16.      * 覆盖默认构造器 
    17.      *  
    18.      * @param countImpl 
    19.      */  
    20.     public CountProxy(CountImpl countImpl) {  
    21.         this.countImpl = countImpl;  
    22.     }  
    23.   
    24.     @Override  
    25.     public void queryCount() {  
    26.         System.out.println("事务处理之前");  
    27.         // 调用委托类的方法;  
    28.         countImpl.queryCount();  
    29.         System.out.println("事务处理之后");  
    30.     }  
    31.   
    32.     @Override  
    33.     public void updateCount() {  
    34.         System.out.println("事务处理之前");  
    35.         // 调用委托类的方法;  
    36.         countImpl.updateCount();  
    37.         System.out.println("事务处理之后");  
    38.   
    39.     }  
    40.   
    41. }  

    运行:

    1. package com.mahoutchina.pattern.proxy;  
    2.   
    3. public class CountTest {  
    4.   
    5.     /** 
    6.      * @param args 
    7.      */  
    8.     public static void main(String[] args) {  
    9.         CountImpl countImpl = new CountImpl();    
    10.         CountProxy countProxy = new CountProxy(countImpl);    
    11.         countProxy.updateCount();    
    12.         countProxy.queryCount();   
    13.   
    14.     }  
    15.   
    16. }  

      从静态代理中可以看出:

        1.接口:代理类需要实现一个接口,这个接口和委托类的接口是一样的,这样proxy才能和委托类行为表现一致

        2. 方法(Method):由于接口限制,proxy类中也要有interface中的各个方法,这就造成了代码重复

       

    4.JDK动态代理实例
        动态代理类克服了proxy需要继承专一的interface接口,并且要实现相应的method的缺陷。从JDK 1.3以来,Java 语言通过java.lang.reflex库提供的三个类直接支持代理:

         java.lang.reflect.Proxy,java.lang.reflect.InvocationHandler 和Method.

        Proxy类在运行时动态创建代理对象,这也是dynamic proxy的由来,下面是类图,其中最重要的是newProxyInstance,这个方法中,指明了将要代理的类的加载器,业务类接口,以及代理类要执行动作的调用处理器(InvokeHandler)

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
    InvocationHandler h) 
                                   throws IllegalArgumentException 
    参数说明: 
    ClassLoader loader:类加载器 
    Class<?>[] interfaces:得到全部的接口 
    InvocationHandler h:得到InvocationHandler接口的子类实例 

    Ps:类加载器 
    在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
    Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
    Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jrelibext目录中的类; 
    AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

       当系统有了一个代理对象之后,对原方法的调用会首先被分派到一个调用处理器(Invocation Handler).InvocationHandler 接口如下图所示:

        

      代码:

        接口:

     
    1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
    2.   
    3. public interface BookFacade {  
    4.     public void addBook();  
    5.     public void deleteBook();  
    6. }  

      实际业务类:

    1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
    2.   
    3. public class BookFacadeImpl implements BookFacade {  
    4.   
    5.     @Override  
    6.     public void addBook() {  
    7.         System.out.println("add book logic is running。。。");   
    8.     }  
    9.   
    10.     @Override  
    11.     public void deleteBook() {  
    12.         System.out.println("delete book logic is running。。。");  
    13.           
    14.     }  
    15.       
    16.   
    17. }  

      动态代理类:

     
    1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
    2.   
    3. import java.lang.reflect.InvocationHandler;  
    4. import java.lang.reflect.Method;  
    5. import java.lang.reflect.Proxy;  
    6.   
    7. public class BookFacadeProxy implements InvocationHandler {  
    8.     private Object target;  
    9.   
    10.     /** 
    11.      *  
    12.      * @param target 
    13.      * @return 
    14.      */  
    15.     public Object bind(Object target) {  
    16.         this.target = target;  
    17.         // 取得代理对象  
    18.         return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
    19.                 target.getClass().getInterfaces(), this);  
    20.     }  
    21.   
    22.     @Override  
    23.     public Object invoke(Object proxy, Method method, Object[] args)  
    24.             throws Throwable {  
    25.         Object result=null;  
    26.         System.out.println("Proxy start...");  
    27.         System.out.println("method name:"+method.getName());  
    28.         result=method.invoke(target, args);  
    29.         System.out.println("Proxy end...");  
    30.         return result;  
    31.     }  
    32.   
    33. }  

      测试类:

      

     
    1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
    2.   
    3. ublic class TestProxy {  
    4.   
    5. /** 
    6.  * @param args 
    7.  */  
    8. public static void main(String[] args) {  
    9.     BookFacadeProxy proxy = new BookFacadeProxy();  
    10.     BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
    11.     bookProxy.addBook();  
    12.     bookProxy.deleteBook();  
    13. }  

       对于JDK 的Proxy,有以下几点:

        1)Interface:对于JDK proxy,业务类是需要一个Interface的,这也是一个缺陷

        2)Proxy,Proxy 类是动态产生的,这个类在调用Proxy.newProxyInstance(targetCls.getClassLoader, targetCls.getInterface,InvocationHander)之后,会产生一个Proxy类的实例。实际上这个Proxy类也是存在的,不仅仅是类的实例。这个Proxy类可以保存到硬盘上。

        3) Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来

        4) InvocationHandler: 这个类在业务委托类执行时,会先调用invoke方法。invoke方法再执行相应的代理操作,可以实现对业务方法的再包装

        5 CGLib 简介

              JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
    示例 

       业务类:

    1. package net.battier.dao;  
    2.   
    3. public interface BookFacade {  
    4.     public void addBook();  
    5. }  
     
    1. package net.battier.dao.impl;  
    2.   
    3. /** 
    4.  * 这个是没有实现接口的实现类 
    5.  *  
    6.  * @author student 
    7.  *  
    8.  */  
    9. public class BookFacadeImpl1 {  
    10.     public void addBook() {  
    11.         System.out.println("增加图书的普通方法...");  
    12.     }  
    13. }  

      代理:

     
    1. package net.battier.proxy;  
    2.   
    3. import java.lang.reflect.Method;  
    4.   
    5. import net.sf.cglib.proxy.Enhancer;  
    6. import net.sf.cglib.proxy.MethodInterceptor;  
    7. import net.sf.cglib.proxy.MethodProxy;  
    8.   
    9. /** 
    10.  * 使用cglib动态代理 
    11.  *  
    12.  * @author student 
    13.  *  
    14.  */  
    15. public class BookFacadeCglib implements MethodInterceptor {  
    16.     private Object target;  
    17.   
    18.     /** 
    19.      * 创建代理对象 
    20.      *  
    21.      * @param target 
    22.      * @return 
    23.      */  
    24.     public Object getInstance(Object target) {  
    25.         this.target = target;  
    26.         Enhancer enhancer = new Enhancer();  
    27.         enhancer.setSuperclass(this.target.getClass());  
    28.         // 回调方法  
    29.         enhancer.setCallback(this);  
    30.         // 创建代理对象  
    31.         return enhancer.create();  
    32.     }  
    33.   
    34.     @Override  
    35.     // 回调方法  
    36.     public Object intercept(Object obj, Method method, Object[] args,  
    37.             MethodProxy proxy) throws Throwable {  
    38.         System.out.println("事物开始");  
    39.         proxy.invokeSuper(obj, args);  
    40.         System.out.println("事物结束");  
    41.         return null;  
    42.   
    43.   
    44.     }  
    45.   
    46. }  

      测试;

       

    [java] view plain copy
     
      1. package net.battier.test;  
      2.   
      3. import net.battier.dao.impl.BookFacadeImpl1;  
      4. import net.battier.proxy.BookFacadeCglib;  
      5.   
      6. public class TestCglib {  
      7.       
      8.     public static void main(String[] args) {  
      9.         BookFacadeCglib cglib=new BookFacadeCglib();  
      10.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
      11.         bookCglib.addBook();  
      12.     }  
      13. }  
  • 相关阅读:
    摩托罗拉SE4500 德州仪器TI Omap37xx/AM3715/DM3730/AM3530 wince6.0/Windows Mobile 6.5平台 二维软解调试记录及相关解释
    摩托罗拉SE4500 三星 S3C6410 Wince6.0平台软解码调试记录以及驱动相关问题解释
    MSM8909+Android5.1.1之系统烧录
    PIC16F914SEG脚中电路图注意事项
    PIC16F914ADC模块采集数据转换
    PIC914AD模块使用记录
    PIC914 LCDCON液晶控制寄存器用法
    PIC914SEG设置方法
    示波器用法
    检测单片机是否启动
  • 原文地址:https://www.cnblogs.com/hoobey/p/6104604.html
Copyright © 2011-2022 走看看