`
hnicypb
  • 浏览: 65084 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

cglib 介绍 原理 使用 demo examples

    博客分类:
  • jar
阅读更多

1.CGLIB包的介绍
    代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,当它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包
    CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
    CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。当不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

CGLIB and ASM
Figure 1: CGLIB Library and ASM Bytecode Framework

图一显示了和CGLIB包和一些框架和语言的关系图。需要注意的是一些框架例如Spring AOP和Hibernate,它们为了满足需要经常同时使用JDK的动态代理和CGLIB包。Hiberater使用JDK的动态代理实现一个专门为 WebShere应用服务器的事务管理适配器;Spring AOP,如果不强制使用CGLIB包,默认情况是使用JDK的动态代理来代理接口。

2.CGLIB 代理的APIS
    CGLIB包的基本代码很少,当学起来有一定的困难,主要是缺少文档,这也是开源软件的一个不足之处。目前CGLIB的版本是(2.1.2),主要由一下部分组成:

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相关的工具类
  • 大多时候,仅仅为了动态地创建代理,你仅需要使用到代理包中很少的一些API。

    正如我们先前所讨论的,CGLIB包是在ASM之上的一个高级别的层。对代理那些没有实现接口的类非常有用。本质上,它是通过动态的生成一个子类去覆盖所要代理类的不是final的方法,并设置好callback,则原有类的每个方法调用就会转变成调用用户定义的拦截方法(interceptors),这比 JDK动态代理方法快多了。

    CGLIB APIs commonly used for proxying classes
  • Figure 2: CGLIB library APIs commonly used for proxying classes

    图2 为我们演示了创建一个具体类的代理时,通常要用到的CGLIB包的APIs。net.sf.cglib.proxy.Callback接口在CGLIB包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。 net.sf.cglib.pr用oxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
    public Object intercept(Object object, java.lang.reflect.Method method,
    Object[] args, MethodProxy proxy) throws Throwable;

  •     当net.sf.cglib.proxy.MethodInterceptor做为所有代理方法的回调(callback)时,当对基于代理的方法调用时,在调用原对象的方法的之前会调用这个方法,如图3所示。第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。在这个方法中,我们可以在调用原方法之前或之后注入自己的代码。

    CGLIB MethodInterceptor
    Figure 3: CGLIB MethodInterceptor


        net.sf.cglib.proxy.MethodInterceptor能够满足任何的拦截(interception )需要,当对有些情况下可能过度。为了简化和提高性能,CGLIB包提供了一些专门的回调(callback)类型。例如:

  • net.sf.cglib.proxy.FixedValue
    为提高性能,FixedValue回调对强制某一特别方法返回固定值是有用的。
  • net.sf.cglib.proxy.NoOp
    NoOp回调把对方法调用直接委派到这个方法在父类中的实现。
  • net.sf.cglib.proxy.LazyLoader
    当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用。
  • net.sf.cglib.proxy.Dispatcher
    Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用。
  • net.sf.cglib.proxy.ProxyRefDispatcher
    ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递。

    如图3所示,代理类的所以方法经常会用到回调(callback),当是你也可以使用net.sf.cglib.proxy.CallbackFilter 有选择的对一些方法使用回调(callback),这种考虑周详的控制特性在JDK的动态代理中是没有的。在JDK代理中,对 java.lang.reflect.InvocationHandler方法的调用对代理类的所以方法都有效。

    除了代理类外,CGLIB通过提供一个对java.lang.reflect.Proxy的drop-in替代来实现对对接口的代理。因为这种代理能力的替代很少被用到,因此相应的APIs也很少提到。

    CGLIB的代理包也对net.sf.cglib.proxy.Mixin提供支持。基本上,它允许多个对象被绑定到一个单个的大对象。在代理中对方法的调用委托到下面相应的对象中。

    接下来我们看看如何使用CGLIB代理APIs创建代理。

    创建一个简单的代理CGLIB代理最核心的是net.sf.cglib.proxy.Enhancer类,为了创建一个代理,最起码你要用到这个类。首先,让我们使用NoOp回调创建一个代理:
    /**
    * Create a proxy using NoOp callback. The target class
    * must have a default zero-argument constructor.
    *
    * @param targetClass the super class of the proxy
    * @return a new proxy for a target class instance
    */
    public Object createProxy(Class targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(NoOp.INSTANCE);
        return enhancer.create();
    }
        返回值是target类一个实例的代理。在这个例子中,我们为net.sf.cglib.proxy.Enhancer 配置了一个单一的回调(callback)。我们可以看到很少直接创建一个简单的代理,而是创建一个 net.sf.cglib.proxy.Enhancer的实例,在net.sf.cglib.proxy.Enhancer类中你可使用静态帮助方法创建一个简单的代理。一般推荐使用上面例子的方法创建代理,因为它允许你通过配置net.sf.cglib.proxy.Enhancer实例很好的控制代理的创建。

        要注意的是,target类是作为产生的代理的父类传进来的。不同于JDK的动态代理,它不能在创建代理时传target对象,target对象必须被CGLIB包来创建。在这个例子中,默认的无参数构造器时用来创建target实例的。如果你想用CGLIB来创建有参数的实例,用net.sf.cglib.proxy.Enhancer.create(Class[], Object[])方法替代net.sf.cglib.proxy.Enhancer.create()就可以了。方法中第一个参数定义了参数的类型,第二个是参数的值。在参数中,基本类型应被转化成类的类型。

  • Use a MethodInterceptor为了更好的使用代理,我们可以使用自己定义的MethodInterceptor类型回调(callback)来代替net.sf.cglib.proxy.NoOp回调。当对代理中所有方法的调用时,都会转向MethodInterceptor类型的拦截(intercept)方法,在拦截方法中再调用底层对象相应的方法。下面我们举个例子,假设你想对目标对象的所有方法调用进行权限的检查,如果没有经过授权,就抛出一个运行时的异常AuthorizationException。其中AuthorizationService.java接口的代码如下:

    package com.lizjason.cglibproxy;

    import java.lang.reflect.Method;

    /**
    * A simple authorization service for illustration purpose.
    *
    * @author Jason Zhicheng Li (jason@lizjason.com)
    */
    public interface AuthorizationService {
        /**
        * Authorization check for a method call. An
    AuthorizationException
        * will be thrown if the check fails.
        */
        void authorize(Method method);
    }

  • net.sf.cglib.proxy.MethodInterceptor接口的实现的类AuthorizationInterceptor.java代码如下:

    package com.lizjason.cglibproxy.impl;

    import java.lang.reflect.Method;

    import net.sf.cglib.proxy.MethodInterceptor;

    import net.sf.cglib.proxy.MethodProxy;

    import com.lizjason.cglibproxy.AuthorizationService;

    /**

    * A simple MethodInterceptor implementation to

    * apply authorization checks for proxy method calls.

    *

    * @author Jason Zhicheng Li (jason@lizjason.com)

    *

    */

    public class AuthorizationInterceptor implements MethodInterceptor {

    private AuthorizationService authorizationService;

    /**

    * Create a AuthorizationInterceptor with the given

    * AuthorizationService

    */

    public AuthorizationInterceptor (AuthorizationService authorizationService) {

    this.authorizationService = authorizationService;

    }

    /**

    * Intercept the proxy method invocations to inject authorization check.

    * The original method is invoked through MethodProxy.

    * @param object the proxy object

    * @param method intercepted Method

    * @param args arguments of the method

    * @param proxy the proxy used to invoke the original method

    * @throws Throwable any exception may be thrown; if so, super method will not be invoked

    * @return any value compatible with the signature of the proxied method.

    */

    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy ) throws Throwable {

    if (authorizationService != null) {

    //may throw an AuthorizationException if authorization failed

    authorizationService.authorize(method);

    }

    return methodProxy.invokeSuper(object, args);

    }

    }


    我们可以看到在拦截方法中,首先进行权限的检查,如果通过权限的检查,拦截方法再调用目标对象的原始方法。由于性能的原因,对原始方法的调用我们使用CGLIBnet.sf.cglib.proxy.MethodProxy对象,而不是反射中一般使用
    java.lang.reflect.Method
    对象。


    Use a CallbackFilter

    net.sf.cglib.proxy.CallbackFilter允许我们在方法层设置回调(callback)。假如你有一个PersistenceServiceImpl类,它有两个方法:saveload,其中方法save需要权限检查,而方法load不需要权限检查。



    package com.lizjason.cglibproxy.impl;

    import com.lizjason.cglibproxy.PersistenceService;

    /**

    * A simple implementation of PersistenceService interface

    *

    * @author Jason Zhicheng Li (jason@lizjason.com)

    */

    public class PersistenceServiceImpl implements PersistenceService {

    public void save(long id, String data) {

    System.out.println(data + " has been saved successfully.");

    }

    public String load(long id) {

    return "Jason Zhicheng Li";

    }

    }

    注意到PersistenceServiceImpl类实现了PersistenceService 接口,因此没有要求要使用CGLIB创建代理。
    net.sf.cglib.proxy.CallbackFilter
    接口的实现如下:

    package com.lizjason.cglibproxy.impl;

    import java.lang.reflect.Method;

    import net.sf.cglib.proxy.CallbackFilter;

    /**

    * An implementation of CallbackFilter for PersistenceServiceImpl

    *

    * @author Jason Zhicheng Li (jason@lizjason.com)

    */

    public class PersistenceServiceCallbackFilter implements CallbackFilter {

    //callback index for save method

    private static final int SAVE = 0;

    //callback index for load method

    private static final int LOAD = 1;

    /**

    * Specify which callback to use for the method being invoked.

    * @method the method being invoked.

    * @return the callback index in the callback array for this method

    */

    public int accept(Method method) {

    String name = method.getName();

    if ("save".equals(name)) {

    return SAVE;

    }

    // for other methods, including the load method, use the

    // second callback

    return LOAD;

    }

    }


    accept
    方法中对代理方法和回调进行了匹配,返回的值是某方法在回调数组中的索引。下面是PersistenceServiceImpl类代理的实现。


    ...

    Enhancer enhancer = new Enhancer();

    enhancer.setSuperclass(PersistenceServiceImpl.class);

    CallbackFilter callbackFilter = new PersistenceServiceCallbackFilter();

    enhancer.setCallbackFilter(callbackFilter);

    AuthorizationService authorizationService = ...

    Callback saveCallback = new AuthorizationInterceptor(authorizationService);

    Callback loadCallback = NoOp.INSTANCE;

    Callback[] callbacks = new Callback[]{saveCallback, loadCallback };

    enhancer.setCallbacks(callbacks);

    ...

    return (PersistenceServiceImpl)enhancer.create();

    在这个例子中save方法使用了AuthorizationInterceptor实例,load方法使用了NoOp实例。此外,你也可以通过
    net.sf.cglib.proxy.Enhancer.setInterfaces(Class[])
    方法指定代理对象所实现的接口。

    除了为net.sf.cglib.proxy.Enhancer指定回调数组,你还可以通过net.sf.cglib.proxy.Enhancer.setCallbackTypes(Class[]) 方法指定回调类型数组。当创建代理时,如果你没有回调实例的数组,就可以使用回调类型。象使用回调一样,你必须使用,net.sf.cglib.proxy.CallbackFilter为每一个方法指定一个回调类型索引。你可以从http://www.lizjason.com/downloads/下载设置回调类型和接口的完整代码。

  • cglib 的几个测试demo


  • 增强一个已有类

    public class MyClass {
     
    	public void method() {
    		System.out.println("MyClass.method()");
    	}
    }
    import java.lang.reflect.Method;
     
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodProxy;
    import net.sf.cglib.proxy.MethodInterceptor;
     
    public class Main {
     
    	public static void main(String[] args) {
     
    		Enhancer enhancer = new Enhancer();
     
    		enhancer.setSuperclass(MyClass.class);
    		enhancer.setCallback( new MethodInterceptorImpl() );
     
     
    		MyClass my = (MyClass)enhancer.create();
     
    		my.method();
    	}
     
    	private static class MethodInterceptorImpl implements MethodInterceptor {
    		
    		public Object intercept(Object obj, 
                                    Method method, 
                                    Object[] args, 
                                    MethodProxy proxy) throws Throwable {
     
    			System.out.println(method);
     
    			proxy.invokeSuper(obj, args);
     
    			return null;
    		}
    	}
    }

    执行结果:

    public void cglib_test.MyClass.method()
    MyClass.method()

    使用CallbackFilter

    public class MyClass {
     
    	public void method() {
    		System.out.println("MyClass.method()");
    	}
     
    	public void method2() {
    		System.out.println("MyClass.method2()");
    	}
    }
    import java.lang.reflect.Method;
     
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodProxy;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.NoOp;
    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.CallbackFilter;
     
     
    public class Main {
     
    	public static void main(String[] args) {
     
    		Callback[] callbacks =
    			new Callback[] { new MethodInterceptorImpl(),  NoOp.INSTANCE };
     
    		Enhancer enhancer = new Enhancer();
     
    		enhancer.setSuperclass(MyClass.class);
    		enhancer.setCallbacks( callbacks );
    		enhancer.setCallbackFilter( new CallbackFilterImpl() );
     
     
    		MyClass my = (MyClass)enhancer.create();
     
    		my.method();
    		my.method2();
    	}
     
    	private static class CallbackFilterImpl implements CallbackFilter {
     
    		public int accept(Method method) {
     
    			if ( method.getName().equals("method2") ) {
    				return 1;
     
    			} else {
    				return 0;
    			}
    		}
    	}
     
    	private static class MethodInterceptorImpl implements MethodInterceptor {
    		
    		public Object intercept(Object obj, 
                                    Method method, 
                                    Object[] args, 
                                    MethodProxy proxy) throws Throwable {
     
    			System.out.println(method);
     
    			return proxy.invokeSuper(obj, args);
    		}
    	}
    }

    执行结果:

    public void cglib_test.MyClass.method()
    MyClass.method()
    MyClass.method2()

    使用Mixin

     

    public interface MyInterfaceA {
     
    	public void methodA();
    }
     
    public interface  MyInterfaceB {
    	public void methodB();
    }
     
    public class MyInterfaceAImpl implements MyInterfaceA {
     
    	public void methodA() {
    		System.out.println("MyInterfaceAImpl.methodA()");
    	}
    }
     
    public class MyInterfaceBImpl implements MyInterfaceB {
     
    	public void methodB() {
    		System.out.println("MyInterfaceBImpl.methodB()");
    	}
    }

     

    import net.sf.cglib.proxy.Mixin;
     
    public class Main {
     
    	public static void main(String[] args) {
     
    		Class[] interfaces =
    			new Class[] { MyInterfaceA.class, MyInterfaceB.class };
    		
    		Object[] delegates =
    			new Object[] { new MyInterfaceAImpl(), new MyInterfaceBImpl() };
    			
    		
    		Object obj = Mixin.create(interfaces, delegates);
     
     
    		MyInterfaceA myA = (MyInterfaceA)obj;
    		myA.methodA();
     
     
    		MyInterfaceB myB = (MyInterfaceB)obj;
    		myB.methodB();
    	}
    }

    执行结果:

     

    MyInterfaceAImpl.methodA()
    MyInterfaceBImpl.methodB()
  • 分享到:
    评论
    1 楼 wangfy1685 2011-11-02  
    写得不错!

    相关推荐

      java cglib和反射demo

      本文将深入探讨这两种技术,并通过一个简单的AOP demo来阐述它们的使用方法。 首先,让我们了解什么是CGLib。CGLib全称为Code Generation Library,是一个Java字节码操纵库,主要用于为类创建子类,从而实现动态...

      CGLIB实现代理demo

      NULL 博文链接:https://huihai.iteye.com/blog/858524

      CGLIB demo

      CGLIB是一个强大的高性能的代码生成库,它在许多AOP(面向切面编程)框架中被使用,如Spring AOP和dynaop等。它允许动态地为一个类创建子类,从而实现方法的拦截。CGLIB是通过字节码技术来实现的,它在运行时为Java类...

      cglib.jar下载

      CGLIB介绍与原理(部分节选自网络) 一、什么是CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要...

      asm + cglib demo

      通过这些示例,你可以学习如何使用ASM和CGlib进行字节码操作,理解它们的工作原理,并将这些技术应用到实际项目中,提高代码的灵活性和可维护性。同时,掌握这两种工具也有助于深入理解Java的运行机制,提升作为Java...

      基于MAVEN项目的CGLib动态代理原理及实现

      在Java编程领域,动态代理是一种...通过理解其工作原理和使用方式,开发者可以更灵活地实现诸如日志记录、性能监控、事务管理等增强功能。结合实际项目需求,合理运用CGLib,可以极大地提升代码的可维护性和扩展性。

      cglib代理模式要使用的相关jar包

      本文将重点介绍使用CGLIB库实现的动态代理。 CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它在许多AOP(面向切面编程)框架中被广泛应用,如Spring AOP。CGLIB通过字节码技术生成代理类,...

      CGLIB依赖jar包

      CGLIB的工作原理是通过字节码生成技术,当调用被代理对象的方法时,实际上是在调用CGLIB生成的子类的方法。它会为原类生成一个子类,并在这个子类的方法上加入拦截器逻辑。由于Java语言规范规定,非final的方法都...

      cglib_cglib.zip

      在实际应用中,理解CGLib的工作原理和如何正确使用回调是非常重要的。这不仅有助于提升代码的灵活性和可维护性,还能有效地利用AOP来解决复杂的问题,例如日志记录、性能分析、权限控制等。 由于CGLib是基于字节码...

      Jdk动态代理和cglib动态代理原理

      以下是JDK动态代理的基本工作原理: 1. **InvocationHandler接口**:这是处理代理对象方法调用的关键接口,定义了一个`invoke()`方法,当调用代理对象的方法时,实际上会调用`invoke()`方法。 2. **Proxy类**:...

      简单实现Cglib子类代理

      下面我们将详细讲解Cglib代理的工作原理以及如何在实际项目中使用。 1. **Cglib代理原理**: - Cglib通过ASM库动态生成一个子类,这个子类继承自目标类,并重写其中的方法。 - 在生成的子类中,每个被代理的方法...

      cglib动态代理介绍

      了解CGlib的工作原理和使用方式,有助于我们在实际开发中更好地利用动态代理实现复杂的功能,提高代码的灵活性和可维护性。在阅读源码时,我们可以深入理解CGlib如何生成子类以及如何进行方法拦截,这对于提升我们的...

      cglib及其依赖包

      CGLib的工作原理是基于ASM库,ASM是一个字节码操作和分析框架,它可以用来动态生成类或增强已存在的Java类的功能。ASM提供了一种直接操作字节码的方法,这使得CGLib能够创建目标类的子类,并在子类中拦截并扩展父类...

      cglib_cglib3.2_remain3gr_cglibjar包_cglib.jar_

      【CGLib:强大的Java代码生成库】 CGLib(Code Generation Library)是一个强大的、高性能的代码生成库,它在运行期扩展Java类与实现Java接口。...正确理解和使用CGLib,能极大地提升开发效率和代码质量。

      cglib2.2.jar

      CGLIB的工作原理大致如下: 1. **创建代理类**:当需要对一个类进行动态代理时,CGLIB会生成一个新的子类,这个子类继承自原始类,并添加了额外的方法用于拦截和处理方法调用。 2. **方法拦截器**:CGLIB使用`...

      CGLib字节码增强实现代理原理(附源码下载)

      在实际应用中,CGLib常与Spring AOP框架结合使用,提供方法级别的拦截。例如,可以利用CGLib实现事务管理,当检测到特定的注解时,自动开启和提交事务。 源码分析是深入理解CGLib工作原理的关键。通过下载并阅读...

      cglib包及依赖汉cglib3.1和asm4.2

      cglib包及依赖汉cglib3.1和asm4.2,主要作用是用户代理,代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常...现在我们可以使用CGLIB包

      cglib的依赖包

      下面我们将详细探讨CGlib的主要功能和使用方法: 1. **动态代理**:CGlib常被用作JDK动态代理的替代方案,特别是当处理的目标类没有实现接口时。通过创建目标类的子类,并在子类中拦截并增强方法调用,CGlib可以...

    Global site tag (gtag.js) - Google Analytics