代理修炼专题

来源:互联网 发布:二级域名和子域名 编辑:程序博客网 时间:2024/04/30 15:29

1.CGlib概述  

     CGlib (code generate library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。 

     自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个

接口。如果想代理没有实现接口的继承的类,该怎么办? CGLIB就是最好的选择。

    CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。其底层是通过小而快的字节码处理框架ASM来转换字节码并生成新的

类。大部分功能实际上是asm所提供的,CGlib只是封装了asm,简化了asm的操作,实现了在运行期动态生成新的class

    ASM 是一个 Java 字节码操纵框架。它可以直接以二进制形式动态地生成 stub 类或其他代理类,或者在装载时动态地修改类。ASM 提供类似于 BCEL 和 SERP 之类的工具包

的功能,但是被设计得更小巧、更快速,这使它适用于实时代码插装

    CGlib被许多AOP的框架使用,例如Spring AOPdynaop,为他们提供方法的interception(拦截);最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(

对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的);EasyMockjMock是通过使用模仿(moke)对象来测试java代码的包,它们都通过使用CGLIB来为那些没

有接口的类创建模仿(moke)对象。

    实际上,CGlibspring aop提供了底层的一种实现;为hibernate使用cglib动态生成VO/PO (接口层对象)。 

2.CGlib APIS

    CGlib包的基本代码很少,但学起来有一定的困难,主要是缺少文档,API描述过于简单,这也是开源软件的一个不足之处。目前CGlib主要由一下部分组成:

  •  net.sf.cglib.core 

       底层字节码处理类,他们大部分与ASM有关系。

  • net.sf.cglib.transform 

       编译期或运行期类和类文件的转换

  • net.sf.cglib.proxy 

       实现创建代理和方法拦截器的类

  •  net.sf.cglib.reflect 

       实现快速反射和C#风格代理的类

  • net.sf.cglib.util 

       集合排序工具类 

  •  net.sf.cglib.beans 

       JavaBean相关的工具类

3.CGlib下载

    1.CGlib的官方网站: https://github.com/cglib/


     2.CGlib目前的最新版本应该是3.1

    3.官网的下载地址 : https://github.com/cglib/cglib/releases


4.Java代理

    代理模式是我们常见的java设计模式,代理模式的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

    代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
    按照代理的创建时期,代理类可以分为两种:
        (1静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
        (2动态代理:在程序运行时,运用反射机制动态创建而成。

5.代理类型

5.1.静态代理

类图:

示例代码:

package com.demo.dao;/** *  * 项目名称:CGlib    * 类名称:Bill    * 类描述:单据的一个接口    * 创建人:YinXiangBing    * 创建时间:2014-5-4 下午04:38:36     * @version 1.0    * */public interface Bill { //查看单据    public void queryBill();        //新增单据      public void newBill();          //修改单据    public void modifyBill();        //删除单据      public void deleteBill();  }package com.demo.dao.impl;import com.demo.dao.Bill;/** *  * 项目名称:CGlib    * 类名称:SaleBill    * 类描述:销售订单DAO实现(委托类) * 创建人:YinXiangBing    * 创建时间:2014-5-4 下午04:55:01     * @version 1.0    * */public class SaleBill implements Bill {public void queryBill() {System.out.println("查询销售订单的方法");  }public void newBill() {System.out.println("新增销售订单的方法");  }  public void modifyBill() {System.out.println("修改销售订单的方法");  }public void deleteBill() {System.out.println("删除销售订单的方法");  }}package com.demo.dao.impl;import com.demo.dao.Bill;/** *  * 项目名称:CGlib    * 类名称:BillProxy    * 类描述:销售订单代理(增强SaleBill实现类)    * 创建人:YinXiangBing    * 创建时间:2014-5-4 下午05:05:33     * @version 1.0    * */public class BillProxy implements Bill {   private SaleBill saleBill;        /**      * 覆盖默认构造器      * @param bill      */      public BillProxy(SaleBill saleBill) {      this.saleBill = saleBill;      }  public void queryBill() { System.out.println("处理之前");       //调用委托类的方法;   saleBill.queryBill();     System.out.println("处理之后");}public void newBill() { System.out.println("处理之前");       //调用委托类的方法;   saleBill.newBill();       System.out.println("处理之后");}public void modifyBill() {System.out.println("处理之前");      // 调用委托类的方法;  saleBill.modifyBill();      System.out.println("处理之后");}public void deleteBill() {System.out.println("处理之前");      // 调用委托类的方法;  saleBill.deleteBill();      System.out.println("处理之后");}}package com.demo.client;import com.demo.dao.impl.SaleBill;import com.demo.dao.impl.BillProxy;/** *  * 项目名称:CGlib    * 类名称:BillClient    * 类描述: 测试单据类 * 创建人:YinXiangBing    * 创建时间:2014-5-4 下午05:19:57     * @version 1.0    * */public class BillClient {public static void main(String[] args) {  SaleBill saleBill = new SaleBill();        BillProxy billProxy = new BillProxy(saleBill);        billProxy.queryBill();      billProxy.newBill();      billProxy.modifyBill();      billProxy.deleteBill();}}

运行结果:

处理之前

查询销售订单的方法

处理之后

处理之前

新增销售订单的方法

处理之后

处理之前

修改销售订单的方法

处理之后

处理之前

删除销售订单的方法

处理之后

    通过这段代码,我们可以看出每一个代理类只能为一个接口服务,在程序开发中必然会产生过多的代理,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则

此时肯定是重复代码。解决这一问题最好的方法是可以通过一个代理类完成全部的代理功能,那么我们就考虑使用动态代理。 

5.2.JDK态代理

    Java对代理模式提供了内建支持见在java.lang.reflect包下面,提供了一个Proxy的类和一个InvocationHandler的接口。
InvocationHandler接口: 
    public interface InvocationHandler { 
           public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
    } 
    参数说明: 
    Object proxy:指被代理的对象。 
    Method method:要调用的方法 
    Object[] args:方法调用时所需要的参数 

    可以将InvocationHandler接口的子类看成一个代理的最终操作类。 

Proxy类: 
    Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) throws IllegalArgumentException 
    参数说明: 
    ClassLoader loader:类加载器 
    Class<?>[] interfaces:得到全部的接口 
    InvocationHandler h:得到InvocationHandler接口的子类实例 

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

类图:

示例代码:

package com.demo.dao;/** *  * 项目名称:CGlib    * 类名称:Order    * 类描述:    * 创建人:YinXiangBing    * 创建时间:2014-5-5 上午09:25:34     * @version 1.0    * */public interface Order {   //增加订单   public void addOrder(String name);     //删除订单   public void deleteOrder(); }package com.demo.dao.impl;import com.demo.dao.Order;/** *  * 项目名称:CGlib    * 类名称:OrderImpl    * 类描述:订单的实现类   * 创建人:YinXiangBing    * 创建时间:2014-5-5 下午01:37:31     * @version 1.0    * */public class OrderImpl implements Order{public void addOrder(String name) {System.out.println("增加订单:"+name);  }public void deleteOrder() {System.out.println("删除订单");  }}package com.demo.dao.impl;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** *  * 项目名称:CGlib    * 类名称:OrderImplProxy    * 类描述: JDK动态订单代理类  * 创建人:YinXiangBing    * 创建时间:2014-5-5 下午01:46:22     * @version 1.0    * */public class OrderProxy implements InvocationHandler {    private Object target;      /**      * 绑定委托对象并返回一个代理类      * @param target      * @return      */      public Object bind(Object target) {          this.target = target;          //取得代理对象          return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)      }         /**      * 调用方法      */      public Object invoke(Object proxy, Method method, Object[] args)              throws Throwable {          Object result=null;          System.out.println("订单处理开始");          //执行方法          result=method.invoke(target, args);          System.out.println("订单处理结束");          return result;      }  }package com.demo.client;import com.demo.dao.Order;import com.demo.dao.impl.OrderImpl;import com.demo.dao.impl.OrderProxy;/** *  * 项目名称:CGlib    * 类名称:OrderClient    * 类描述: 测试订单类 * 创建人:YinXiangBing    * 创建时间:2014-5-5 下午01:52:29     * @version 1.0    * */public class OrderClient { public static void main(String[] args) {     OrderProxy proxy = new OrderProxy();     Order orderProxy = (Order) proxy.bind(new OrderImpl());     orderProxy.addOrder("书籍");     orderProxy.deleteOrder();}}

运行结果:

订单处理开始

增加订单:书籍

订单处理结束

订单处理开始

删除订单

订单处理结束

     静态代理:实现的时候,接口定义很多的方法,代理类自然要实现很多方法。静态代理需要程序员手工编写。

     动态代理:实现的时候,接口定义了很多方法,但动态代理类只有一个invoke,当接口发生变化时,动态代理的接口不需要跟着变化。动态代理类的字节码在程序运行时

Java反射机制动态生成,无需程序员手工编写它的源代码,简化了编程工作,提高了软件系统可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。

     Java的动态代理目前只能代理接口,基本的实现是依靠Java的发射机制和动态生成class的技术,来动态生成被代理的接口的实现对象。如果要实现类的代理,这就要使用

CGlib动态代理了。

5.3.CGlib动态代理 

    CGlib是针对类来实现代理的,原理是对指定的目标的类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

类图:


示例代码:

package com.demo.dao.impl;/** *  * 项目名称:CGlib    * 类名称:Course    * 类描述:课程    * 创建人:YinXiangBing    * 创建时间:2014-5-6 下午01:37:29     * @version 6.0    * */public class Course {     public void choiceCourse(String name){     System.out.println("你选择的课程是:"+name);     }}package com.demo.dao.impl;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** *  * 项目名称:CGlib    * 类名称:CourseProxy    * 类描述:CGlib动态代理     * 创建人:YinXiangBing    * 创建时间:2014-5-6 下午01:45:15     * @version 6.0    * */public class CourseProxy implements MethodInterceptor { private Object target;      /**    * 创建代理对象     * @param target    * @return Object   */     public Object getInstance(Object target) {          this.target = target;          Enhancer enhancer = new Enhancer();          enhancer.setSuperclass(this.target.getClass());          //回调方法          enhancer.setCallback(this);          //创建代理对象          return enhancer.create();      }     //回调方法     public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {    System.out.println("处理开始......");          proxy.invokeSuper(obj, args);          System.out.println("处理结束......");      return null;   }}package com.demo.client;import com.demo.dao.impl.Course;import com.demo.dao.impl.CourseProxy;/** *  * 项目名称:CGlib    * 类名称:CourseClient    * 类描述:动态代理测试类    * 创建人:YinXiangBing    * 创建时间:2014-5-6 下午01:53:42     * @version 6.0    * */public class CourseClient {public static void main(String[] args) {   CourseProxy proxy = new CourseProxy();   Course course = (Course) proxy.getInstance(new Course());   course.choiceCourse("线性代数");}}

运行结果:

处理开始......

你选择的课程是:线性代数

处理结束......



0 0
原创粉丝点击