原创学习CGLIB动态代理中遇到的问题

Posted caogen1991

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创学习CGLIB动态代理中遇到的问题相关的知识,希望对你有一定的参考价值。

代码清单1 CGLIB动态代理

 

 1 package wulj.proxy.cglibProxy;
 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 public class CglibProxyExample implements MethodInterceptor {
10 
11     /**
12      * 代理逻辑方法
13      * @param proxy 代理对象
14      * @param method 方法
15      * @param args 方法参数
16      * @param methodProxy 方法代理
17      * @return 代理逻辑返回
18      * @throws Throwable 异常
19      * 
20      */
21     @Override
22     public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
23         System.out.println("调用真实对象前");
24         //CGLIB反射调用真实对象方法
25         Object result = methodProxy.invokeSuper(proxy, args);
26         System.out.println("调用真实对象后");
27         return result;
28     }
29     
30     /**
31      * 生成CGLIB代理对象
32      * @param cls     Class类
33      * @return  Class类的CGLIB代理对象
34      */
35     public Object getProxy(Class<?> cls){
36         //CGLIB enhancer 增强类对象
37         Enhancer enhancer = new Enhancer();
38         //设置增强类型
39         enhancer.setSuperclass(cls);
40         //定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
41         enhancer.setCallback(this);
42         //生成并返回代理对象
43         return enhancer.create();
44         
45     }
46 
47 }

代码清单2 真实对象

 1 package wulj.proxy;
 2 
 3 public class ReflectServiceImpl {
 4     private String name = "";
 5     public void sayHello(String name){
 6         System.out.println(name);
 7     }
 8     public String getName() {
 9         return name;
10     }
11     public void setName(String name) {
12         this.name = name;
13     }
14 
15 }

 

代码清单3 测试类

 1 package wulj.proxy.cglibProxy;
 2 
 3 import wulj.reflect.ReflectServiceImpl;
 4 
 5 public class TestCGLIbProxyMain {
 6 
 7     public static void main(String[] args) {
 8         CglibProxyExample cpe = new CglibProxyExample();
 9         ReflectServiceImpl obj = (ReflectServiceImpl) cpe.getProxy(ReflectServiceImpl.class);//获得代理对象
10         obj.sayHello("hello,world!");//调用逻辑处理方法
11     }
12 }

原本只引入了cglib-3.2.5.jar,执行main方法时报错如下:

Exception in thread "main" java.lang.NoClassDefFoundError: org/objectweb/asm/Type
    at net.sf.cglib.core.TypeUtils.parseType(TypeUtils.java:184)
    at net.sf.cglib.core.KeyFactory.<clinit>(KeyFactory.java:72)
    at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:72)
    at wulj.proxy.cglibProxy.CglibProxyExample.getProxy(CglibProxyExample.java:37)
    at wulj.proxy.cglibProxy.TestCGLIbProxyMain.main(TestCGLIbProxyMain.java:9)
Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 5 more

 

 报错显示有找不到的类,上网查了一下知道了很多java字节码操作和分析的第三方类库都引用了asm.jar文件,由于工程不是Maven管理的,无法解决依赖传递问题,所以要手动引入asm.jar文件。把asm.jar文件添加到项目路径里,运行,然后就正常了,此处参考:https://www.cnblogs.com/gl-developer/p/7115644.html

 

引入asm-3.3.1.jar后执行main方法是,又报下面的错: 

Exception in thread "main" java.lang.ExceptionInInitializerError
    at wulj.proxy.cglibProxy.CglibProxyExample.getProxy(CglibProxyExample.java:37)
    at wulj.proxy.cglibProxy.TestCGLIbProxyMain.main(TestCGLIbProxyMain.java:9)
Caused by: java.lang.IllegalStateException: Unable to load cache item
    at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:79)
    at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
    at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:174)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:153)
    at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)
    ... 2 more
Caused by: java.lang.IncompatibleClassChangeError: class net.sf.cglib.core.DebuggingClassWriter has interface org.objectweb.asm.ClassVisitor as super class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$100(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at net.sf.cglib.core.DefaultGeneratorStrategy.getClassVisitor(DefaultGeneratorStrategy.java:30)
    at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:24)
    at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:329)
    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
    at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
    ... 9 more

 

参考:http://blog.csdn.net/yuanlaishinizhu/article/details/12998847,找到解决方案,原因是:cglib版本为3.0以上,org.objectweb.asm版本为3.1.0时,版本冲突,报错java.lang.IncompatibleClassChangeError: class net.sf.cglib.core.DebuggingClassWriter has interface org.objectweb.asm.ClassVisitor as super class

使用cglib 2.2 可解决此问题,该版本中的DebuggingClassWriter的父类为ClassWriter

执行main方法:问题解决:

调用真实对象前
hello,world!
调用真实对象后

 

以上是关于原创学习CGLIB动态代理中遇到的问题的主要内容,如果未能解决你的问题,请参考以下文章

CgLib动态代理学习Spring AOP基础之一

动态代理之 CGLIB 动态代理

jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

使用CGLIB实现动态代理

尚硅谷设计模式学习(13)---[代理模式(Proxy)---静态代理,动态代理,Cglib代理]

AOP 学习笔记