`
qizhangwan
  • 浏览: 33153 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

CGLIB

阅读更多
CGlib概述:
cglib(Code Generation Library )是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
cglib封装了asm,可以在运行期动态生成新的class。
cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。

CGlib应用:
以一个实例在简单介绍下cglib的应用。
我们模拟一个虚拟的场景,关于信息的管理。

1)原始需求是任何人可以操作信息的create,update,delete,query操作。
InfoManager.java --封装对信息的操作

public   class  InfoManager {
     //  模拟查询操作
     public   void  query() {
        System.out.println( " query " );
    }
     //  模拟创建操作
     public   void  create() {
        System.out.println( " create " );
    }
     //  模拟更新操作
     public   void  update() {
        System.out.println( " update " );
    }
     //  模拟删除操作
     public   void  delete() {
        System.out.println( " delete " );
    }
}
InfoManagerFactory.java --工厂类

public   class  InfoManagerFactory {
     private   static  InfoManager manger  =   new  InfoManager();
     /**
     * 创建原始的InfoManager
     *
     *  @return
      */
     public   static  InfoManager getInstance() {
         return  manger;
    }
}
client.java --供客户端调用

public   class  Client {

     public   static   void  main(String[] args) {
        Client c  =   new  Client();
        c.anyonecanManager();
    }

     /**
     * 模拟:没有任何权限要求,任何人都可以操作
      */
     public   void  anyonecanManager() {
        System.out.println( " any one can do manager " );
        InfoManager manager  =  InfoManagerFactory.getInstance();
        doCRUD(manager);
        separatorLine();
    }

     /**
     * 对Info做增加/更新/删除/查询操作
     *
     *  @param  manager
      */
     private   void  doCRUD(InfoManager manager) {
        manager.create();
        manager.update();
        manager.delete();
        manager.query();
    }

     /**
     * 加一个分隔行,用于区分
      */
     private   void  separatorLine() {
        System.out.println( " ################################ " );
    }

}
至此,没有涉及到cglib的内容,因为需求太简单了,但是接下来,需求发生了改变,要求:

2)只有一个叫“maurice”的用户登录,才允许对信息进行create,update,delete,query的操作。
怎么办?难道在每个方法前,都加上一个权限判断吗?这样重复逻辑太多了,于是乎想到了Proxy(代理模式),但是原先的InfoManager也没有实现接口,不能采用jdk的proxy。那么cglib在这边就要隆重登场。
一旦使用cgblig,只需要添加一个MethodInterceptor的类以及修改factory代码就可以实现这个需求。
AuthProxy.java --权限校验代理类

public   class  AuthProxy  implements  MethodInterceptor {

     private  String name;  //  会员登录名

     public  AuthProxy(String name) {
         this .name  =  name;
    }

     /**
     * 权限校验,如果会员名为:maurice,则有权限做操作,否则提示没有权限
      */
    @Override
     public  Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)  throws  Throwable {
         if  ( ! " maurice " .equals( this .name)) {
            System.out.println( " AuthProxy:you have no permits to do manager! " );
             return   null ;
        }
         return  proxy.invokeSuper(obj, args);
    }

     public  String getName() {
         return  name;
    }

     public   void  setName(String name) {
         this .name  =  name;
    }

}
InfoManagerFactory.java --代码变动如下:

public   class  InfoManagerFactory {

     /**
     * 创建带有权限检验的InfoManager
     *
     *  @param  auth
     *  @return
      */
     public   static  InfoManager getAuthInstance(AuthProxy auth) {
        Enhancer enhancer  =   new  Enhancer();
        enhancer.setSuperclass(InfoManager. class );
        enhancer.setCallback(auth);
         return  (InfoManager) enhancer.create();
    }

   
}

client.java --代码修改如下

public   class  Client {

     public   static   void  main(String[] args) {
        Client c  =   new  Client();
        c.haveNoAuthManager();
        c.haveAuthManager();
    }

     /**
     * 模拟:登录会员没有权限
      */
     public   void  haveNoAuthManager() {
        System.out.println( " the loginer's name is not maurice,so have no permits do manager " );
        InfoManager noAuthManager  =  InfoManagerFactory.getAuthInstance( new  AuthProxy( " maurice1 " ));
        doCRUD(noAuthManager);
        separatorLine();
    }

     /**
     * 模拟:登录会员有权限
      */
     public   void  haveAuthManager() {
        System.out.println( " the loginer's name is maurice,so have permits do manager " );
        InfoManager authManager  =  InfoManagerFactory.getAuthInstance( new  AuthProxy( " maurice " ));
        doCRUD(authManager);
        separatorLine();
    }

     /**
     * 对Info做增加/更新/删除/查询操作
     *
     *  @param  manager
      */
     private   void  doCRUD(InfoManager manager) {
        manager.create();
        manager.update();
        manager.delete();
        manager.query();
    }

     /**
     * 加一个分隔行,用于区分
      */
     private   void  separatorLine() {
        System.out.println( " ################################ " );
    }

}
执行下代码,发现这时client端中已经加上了权限校验。
同样是InfoManager,为什么这时能多了权限的判断呢?Factory中enhancer.create()返回的到底是什么对象呢?这个疑问将在第三部分CGlib中解释。
这边的代码,其实是介绍了cglib中的enhancer功能.

到这里,参照上面的代码,就可以使用cglib带来的aop功能了。但是为了更多介绍下cglib的功能,模拟需求再次发生变化:

3)由于query功能用户maurice才能使用,招来其他用户的强烈的抱怨,所以权限再次变更,只有create,update,delete,才需要权限保护,query任何人都可以使用。
怎么办?采用AuthProxy,使得InfoManager中的所有方法都被代理,加上了权限的判断。当然,最容易想到的办法,就是在AuthProxy 的intercept的方法中再做下判断,如果代理的method是query,不需要权限验证。这么做,可以,但是一旦逻辑比较复杂的时候,intercept这个方法要做的事情会很多,逻辑会异常的复杂。
幸好,cglib还提供了CallbackFilter。使用CallbackFilter,可以明确表明,被代理的类(InfoManager)中不同的方法,被哪个拦截器(interceptor)拦截。
AuthProxyFilter.java


public   class  AuthProxyFilter  implements  CallbackFilter {

     private   static   final   int  AUTH_NEED      =   0 ;
     private   static   final   int  AUTH_NOT_NEED  =   1 ;

     /**
     * <pre>
     * 选择使用的proxy
     * 如果调用query函数,则使用第二个proxy
     * 否则,使用第一个proxy
     * </pre>
      */
    @Override
     public   int  accept(Method method) {
         if  ( " query " .equals(method.getName())) {
             return  AUTH_NOT_NEED;
        }
         return  AUTH_NEED;
    }

}
这段代码什么意思?其中的accept方法的意思是说,如果代理的方法是query(),那么使用第二个拦截器去拦截,如果代理的方法不是 query(),那么使用第一个拦截器去拦截。所以我们只要再写一个拦截器,不做权限校验就行了。(其实,cglib中的NoOp.INSTANCE就是一个空的拦截器,只要配置上这个就可以了。)
InfoManagerFactory.java --代码修改如下:(配置不同的拦截器和filter)

public   class  InfoManagerFactory {

     /**
     * 创建不同权限要求的InfoManager
     *
     *  @param  auth
     *  @return
      */
     public   static  InfoManager getSelectivityAuthInstance(AuthProxy auth) {
        Enhancer enhancer  =   new  Enhancer();
        enhancer.setSuperclass(InfoManager. class );
        enhancer.setCallbacks( new  Callback[] { auth, NoOp.INSTANCE });
        enhancer.setCallbackFilter( new  AuthProxyFilter());
         return  (InfoManager) enhancer.create();
    }

}
记住:setCallbacks中的拦截器(interceptor)的顺序,一定要和CallbackFilter里面指定的顺序一致!!切忌。

Client.java


public   class  Client {

     public   static   void  main(String[] args) {
        Client c  =   new  Client();
        c.selectivityAuthManager();
    }
   
     /**
     * 模拟:没有权限的会员,可以作查询操作
      */
     public   void  selectivityAuthManager() {
        System.out.println( " the loginer's name is not maurice,so have no permits do manager except do query operator " );
        InfoManager authManager  =  InfoManagerFactory.getSelectivityAuthInstance( new  AuthProxy( " maurice1 " ));
        doCRUD(authManager);
        separatorLine();
    }

     /**
     * 对Info做增加/更新/删除/查询操作
     *
     *  @param  manager
      */
     private   void  doCRUD(InfoManager manager) {
        manager.create();
        manager.update();
        manager.delete();
        manager.query();
    }

     /**
     * 加一个分隔行,用于区分
      */
     private   void  separatorLine() {
        System.out.println( " ################################ " );
    }

}
此时,对于query的权限校验已经被去掉了。


通过一个模拟需求,简单介绍了cglib aop功能的使用。
CGlib应用非常广,在spring,hibernate等框架中,被大量的使用。


CGlib原理:
cglib神奇吗?其实一旦了解cglib enhancer的原理,一切就真相大白了。
刚才在第二部分中,有个疑问:enhancer.create()到底返回了什么对象?

其实在刚才的例子中,cglib在代码运行期,动态生成了InfoManager的子类,并且根据CallbackFilter的accept方法,覆写了InfoManager中的所有方法--去执行相应的MethodInterceptor的intercept方法。

有兴趣的朋友可以看看我反编译的InfoManager的子类,就可以很明白知道具体的实现了。(需要有耐心才可以)
InfoManager$$EnhancerByCGLIB$$de624598.jad


//  Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
//  Jad home page:  http://www.geocities.com/kpdus/jad.html
//  Decompiler options: packimports(3)
//  Source File Name:   <generated>

package  cn.eulic.codelab.cglib;

import  java.lang.reflect.Method;
import  net.sf.cglib.core.Signature;
import  net.sf.cglib.proxy. * ;

//  Referenced classes of package cn.eulic.codelab.cglib:
//             InfoManager

public   class  CGLIB.BIND_CALLBACKS  extends  InfoManager
     implements  Factory
{

     static   void  CGLIB$STATICHOOK1()
    {
        Class class1;
        ClassLoader classloader;
        CGLIB$THREAD_CALLBACKS  =   new  ThreadLocal();
        classloader  =  (class1  =  Class.forName( " cn.eulic.codelab.cglib.InfoManager$$EnhancerByCGLIB$$de624598 " )).getClassLoader();
        classloader;
        CGLIB$emptyArgs  =   new  Object[ 0 ];
        CGLIB$delete$ 0 $Proxy  =  MethodProxy.create(classloader, (CGLIB$delete$ 0 $Method  =  Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " delete " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()V " ,  " delete " ,  " CGLIB$delete$0 " );
        CGLIB$create$ 1 $Proxy  =  MethodProxy.create(classloader, (CGLIB$create$ 1 $Method  =  Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " create " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()V " ,  " create " ,  " CGLIB$create$1 " );
        CGLIB$query$ 2 $Proxy  =  MethodProxy.create(classloader, (CGLIB$query$ 2 $Method  =  Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " query " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()V " ,  " query " ,  " CGLIB$query$2 " );
        CGLIB$update$ 3 $Proxy  =  MethodProxy.create(classloader, (CGLIB$update$ 3 $Method  =  Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " update " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()V " ,  " update " ,  " CGLIB$update$3 " );
        CGLIB$finalize$ 4 $Proxy  =  MethodProxy.create(classloader, (CGLIB$finalize$ 4 $Method  =  Class.forName( " java.lang.Object " ).getDeclaredMethod( " finalize " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()V " ,  " finalize " ,  " CGLIB$finalize$4 " );
        CGLIB$hashCode$ 5 $Proxy  =  MethodProxy.create(classloader, (CGLIB$hashCode$ 5 $Method  =  Class.forName( " java.lang.Object " ).getDeclaredMethod( " hashCode " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()I " ,  " hashCode " ,  " CGLIB$hashCode$5 " );
        CGLIB$clone$ 6 $Proxy  =  MethodProxy.create(classloader, (CGLIB$clone$ 6 $Method  =  Class.forName( " java.lang.Object " ).getDeclaredMethod( " clone " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()Ljava/lang/Object; " ,  " clone " ,  " CGLIB$clone$6 " );
        CGLIB$equals$ 7 $Proxy  =  MethodProxy.create(classloader, (CGLIB$equals$ 7 $Method  =  Class.forName( " java.lang.Object " ).getDeclaredMethod( " equals " ,  new  Class[] {
            Class.forName( " java.lang.Object " )
        })).getDeclaringClass(), class1,  " (Ljava/lang/Object;)Z " ,  " equals " ,  " CGLIB$equals$7 " );
        CGLIB$toString$ 8 $Proxy  =  MethodProxy.create(classloader, (CGLIB$toString$ 8 $Method  =  Class.forName( " java.lang.Object " ).getDeclaredMethod( " toString " ,  new  Class[ 0 ])).getDeclaringClass(), class1,  " ()Ljava/lang/String; " ,  " toString " ,  " CGLIB$toString$8 " );
         return ;
    }

     final   void  CGLIB$delete$ 0 ()
    {
         super .delete();
    }

     public   final   void  delete()
    {
        CGLIB$CALLBACK_0;
         if (CGLIB$CALLBACK_0  !=   null )  goto  _L2;  else   goto  _L1
_L1:
        JVM INSTR pop ;
        CGLIB$BIND_CALLBACKS( this );
        CGLIB$CALLBACK_0;
_L2:
        JVM INSTR dup ;
        JVM INSTR ifnull  37 ;
            goto  _L3 _L4
_L3:
         break  MISSING_BLOCK_LABEL_21;
_L4:
         break  MISSING_BLOCK_LABEL_37;
         this ;
        CGLIB$delete$ 0 $Method;
        CGLIB$emptyArgs;
        CGLIB$delete$ 0 $Proxy;
        intercept();
         return ;
         super .delete();
         return ;
    }

     final   void  CGLIB$create$ 1 ()
    {
         super .create();
    }

     public   final   void  create()
    {
        CGLIB$CALLBACK_0;
         if (CGLIB$CALLBACK_0  !=   null )  goto  _L2;  else   goto  _L1
_L1:
        JVM INSTR pop ;
        CGLIB$BIND_CALLBACKS( this );
        CGLIB$CALLBACK_0;
_L2:
        JVM INSTR dup ;
        JVM INSTR ifnull  37 ;
            goto  _L3 _L4
_L3:
         break  MISSING_BLOCK_LABEL_21;
_L4:
         break  MISSING_BLOCK_LABEL_37;
         this ;
        CGLIB$create$ 1 $Method;
        CGLIB$emptyArgs;
        CGLIB$create$ 1 $Proxy;
        intercept();
         return ;
         super .create();
         return ;
    }

     final   void  CGLIB$query$ 2 ()
    {
         super .query();
    }

     public   final   void  query()
    {
        CGLIB$CALLBACK_0;
         if (CGLIB$CALLBACK_0  !=   null )  goto  _L2;  else   goto  _L1
_L1:
        JVM INSTR pop ;
        CGLIB$BIND_CALLBACKS( this );
        CGLIB$CALLBACK_0;
_L2:
        JVM INSTR dup ;
        JVM INSTR ifnull  37 ;
            goto  _L3 _L4
_L3:
         break  MISSING_BLOCK_LABEL_21;
_L4:
         break  MISSING_BLOCK_LABEL_37;
         this ;
        CGLIB$query$ 2 $Method;
        CGLIB$emptyArgs;
        CGLIB$query$ 2 $Proxy;
        intercept();
         return ;
         super .query();
         return ;
    }

     final   void  CGLIB$update$ 3 ()
    {
         super .update();
    }

     public   final   void  update()
    {
        CGLIB$CALLBACK_0;
         if (CGLIB$CALLBACK_0  !=   null )  goto  _L2;  else   goto  _L1
_L1:
        JVM INSTR pop ;
        CGLIB$BIND_CALLBACKS( this );
        CGLIB$CALLBACK_0;
_L2:
        JVM INSTR dup ;
        JVM INSTR ifnull  37 ;
            goto  _L3 _L4
_L3:
         break  MISSING_BLOCK_LABEL_21;
_L4:
         break  MISSING_BLOCK_LABEL_37;
         this ;
        CGLIB$update$ 3 $Method;
        CGLIB$emptyArgs;
        CGLIB$update$ 3 $Proxy;
        intercept();
         return ;
         super .update();
         return ;
    }

     final   void  CGLIB$finalize$ 4 ()
         throws  Throwable
    {
         super .finalize();
    }

     protected   final   void  finalize()
         throws  Throwable
    {
        CGLIB$CALLBACK_0;
         if (CGLIB$CALLBACK_0  !=   null )  goto  _L2;  else   goto  _L1
_L1:
        JVM INSTR pop ;
        CGLIB$BIND_CALLBACKS( this );
        CGLIB$CALLBACK_0;
_L2:
        JVM INSTR dup ;
        JVM INSTR ifnull  37 ;
            goto  _L3 _L4
_L3:
         break  MISSING_BLOCK_LABEL_21;
_L4:
         break  MISSING_BLOCK_LABEL_37;
         this ;
        CGLIB$finalize$ 4 $Method;
        CGLIB$emptyArgs;
        CGLIB$finalize$ 4 $Proxy;
        intercept();
         return ;
         super .finalize();
         return ;
    }

     final   int  CGLIB$hashCode$ 5 ()
    {
         return   super .hashCode();
    }

     public   final   int  hashCode()
    {
        CGLIB$CALLBACK_0;
         if (CGLIB$CALLBACK_0  !=   null )  goto  _L2;  else   goto  _L1
_L1:
        JVM INSTR pop ;
        CGLIB$BIND_CALLBACKS( this );
        CGLIB$CALLBACK_0;
_L2:
        JVM INSTR dup ;
        JVM INSTR ifnull  52 ;
            goto  _L3 _L4
_L3:
         this ;
        CGLIB$hashCode$ 5 $Method;
        CGLIB$emptyArgs;
        CGLIB$hashCode$ 5 $Proxy;
        intercept();
        JVM INSTR dup ;
        JVM INSTR ifnonnull  45 ;
            goto  _L
分享到:
评论

相关推荐

    cglib.jar下载

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

    CGLIB依赖jar包

    CGLIB,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在Java世界里被广泛应用,尤其是在Spring框架中。CGLIB是基于ASM(一个底层的Java字节码操作和分析框架)来实现的,它允许开发者在运行时...

    cglib的依赖包

    CGlib,全称为Code Generation Library,是一个强大的Java代码生成库,广泛用于动态代理、AOP(面向切面编程)框架以及性能优化等场景。它通过字节码技术为类创建子类,从而实现对目标类的功能增强。在Java中,由于...

    CGLIB需要的asm-2.2.3.jar和cglib-nodep-2.2.jar

    CGLIB,全称为Code Generation Library,是一个强大的高性能的代码生成库,被广泛应用于Java世界,尤其是Spring框架中。它允许程序在运行时动态地创建Java对象并扩展已有类的功能。CGLIB是通过字节码技术实现的,而...

    cglib-3.1-API文档-中文版.zip

    赠送jar包:cglib-3.1.jar; 赠送原API文档:cglib-3.1-javadoc.jar; 赠送源代码:cglib-3.1-sources.jar; 赠送Maven依赖信息文件:cglib-3.1.pom; 包含翻译后的API文档:cglib-3.1-javadoc-API文档-中文(简体)版...

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

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

    cglib_cglib3.2_remain3gr_cglibjar包_cglib.jar_

    【CGLib:强大的Java代码生成库】 CGLib(Code Generation Library)是一个强大的、高性能的代码生成库,它在运行期扩展Java类与实现Java接口。这个库最初是为EJB的透明代理而设计的,但后来发展成为了一个广泛的...

    cglib及其依赖包

    CGLib,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在Java世界中被广泛应用,尤其是在动态代理和AOP(面向切面编程)领域。这个库的主要功能是能够在运行时动态创建类或者增强已有类的功能...

    Cglib3.3.0最新版jar包

    Cglib是一个强大的、高性能的代码生成库,它在Java世界中被广泛应用,尤其是在动态代理和AOP(面向切面编程)领域。Cglib3.3.0是该库的最新版本,提供了两个jar包:`cglib-3.3.0.jar`和`cglib-nodep-3.3.0.jar`。 1...

    cglib2.2.jar

    CGLIB,全称为Code Generation Library,是一个非常强大的Java字节码操纵和动态代理框架。它在Java编程中扮演着重要角色,特别是在AOP(面向切面编程)和ORM(对象关系映射)框架中,如Spring AOP和Hibernate。这个...

    cglib-nodep-3.2.4-API文档-中文版.zip

    赠送jar包:cglib-nodep-3.2.4.jar; 赠送原API文档:cglib-nodep-3.2.4-javadoc.jar; 赠送源代码:cglib-nodep-3.2.4-sources.jar; 赠送Maven依赖信息文件:cglib-nodep-3.2.4.pom; 包含翻译后的API文档:cglib-...

    cglib.jar | asm.jar对应版本

    其中,`cglib.jar` 和 `asm.jar` 是实现Java动态代理的两个关键库,它们在许多框架和库中都有广泛的应用,比如Spring AOP和Hibernate。 `cglib.jar` 是一个强大的代码生成库,全称为Code Generation Library。它...

    CGLib3.2.5依赖包及源码

    CGLib,全称为Code Generation Library,是一个强大的Java字节码操作库,广泛应用于动态代理、AOP(面向切面编程)以及性能优化等领域。它允许开发者在运行时创建和增强新的类或对象,而无需编写任何Java源代码。...

    cglib必须导入的包和案例

    Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展. JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现....

    cglib-3.3.0.jar,asm-7.0.jar

    这里提到的"cglib-3.3.0.jar"和"asm-7.0.jar"是两个与Java动态代理密切相关的库。 首先,`cglib-3.3.0.jar`是Code Generation Library的简称,它是一个强大的高性能的代码生成库,广泛用于Java AOP(面向切面编程)...

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

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

    JAVA JDK静态代理、动态代理、CGlib代理的代码演示

    Java提供了两种主要的代理实现方式:JDK静态代理和动态代理,另外还有第三方库如CGlib提供的代理实现。下面我们将详细探讨这些代理技术,并通过代码演示来理解它们的工作原理。 ### 1. JDK静态代理 静态代理是我们...

    cglib_cglib.zip

    CGLib,全称为Code Generation Library,是一个强大的Java代码生成库,广泛用于动态代理、AOP(面向切面编程)等领域。它允许开发者在运行时创建和扩展Java类,而无需直接编写新的源代码或编译步骤。这个压缩包...

    cglib-2.2.2.jar(修订版)

    at net.sf.cglib.core.ReflectUtils.getMethodInfo(ReflectUtils.java:424) at net.sf.cglib.beans.BeanCopier$Generator.generateClass(BeanCopier.java:133) at ...

Global site tag (gtag.js) - Google Analytics