《Java知识应用》Java CGLib动态代理使用和原理说明
一、CGLib jar包下载
百度网盘:
链接:https://pan.baidu.com/s/1O_5o_vtPWEZ3Hy0CHlZDug
提取码:5wf6
CGLib要使用还需要额外的asm.jar
链接:https://pan.baidu.com/s/1874lFlpOLsdzPUs7O9Ol-g
提取码:wf68
二、CGLib应用案例
package demo.knowledgepoints.cglib; public class BaseDemo { private String Name; public String getName() { return Name; } public void setName(String name) { Name = name; } @Override public String toString() { return "BaseDemo{" + "Name='" + Name + '\'' + '}'; } }
package demo.knowledgepoints.cglib; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("=============执行自己想要的内容start================"); System.out.println("method.getName():" + method.getName()); Object object = methodProxy.invokeSuper(o,objects); System.out.println("=============执行自己想要的内容end================"); return object; } }
package demo.knowledgepoints.cglib; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; public class CGLibTest { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "src\\demo\\knowledgepoints\\cglib"); /** * 该类为CGLib设置动态代理的核心,你设置一个怎么样的动态代理 */ Enhancer enhancer = new Enhancer(); /*******设置需要被代理的类**************/ enhancer.setSuperclass(BaseDemo.class); /*******设置代理类**************/ enhancer.setCallback(new MyMethodInterceptor()); /*******创建代理类**************/ BaseDemo proxyBaseDemo = (BaseDemo)enhancer.create(); proxyBaseDemo.setName("李磊"); } }
运行结果:
这里会出现一个比较有意思的情况,如果是dubug运行会出现如下打印信息
简单解释一下:因为IDEA duebug下,你会需要查询信息,而这些信息其实就是IDEA默认在调用你对象的toString方法。IDEA执行的toString当然也被代理了。
三、CGLib动态代理原理
CGLib动态代理原理和JDK动态原理本质区别很大。
CGLib动态代理原理:是通过子类继承来实现动态代理的。上面的应用程序我们已经将CGLib的代理类生成到本地:
我们可以看看反编译后里面的代码。
public class BaseDemo$$EnhancerByCGLIB$$3c73e677 extends BaseDemo implements Factory{ final String CGLIB$toString$0() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$0$Method, CGLIB$emptyArgs, CGLIB$toString$0$Proxy) : super.toString(); } final String CGLIB$getName$1() { return super.getName(); } public final String getName() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$getName$1$Method, CGLIB$emptyArgs, CGLIB$getName$1$Proxy) : super.getName(); } final void CGLIB$setName$2(String var1) { super.setName(var1); } public final void setName(String var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { var10000.intercept(this, CGLIB$setName$2$Method, new Object[]{var1}, CGLIB$setName$2$Proxy); } else { super.setName(var1); } } }
上述代码是我取了其中比较重要的信息,真实代理类,还会多一些代码。
从上面的文件内容可以看出:
1. 继承了BaseDemo
2. 实现Factory 接口,该接口可以创建对象等功能。
3. 重写了父类方法,并且还是会调用原父类方法。
更多使用方法见CGLib API :http://devdoc.net/javamisc/cglib-3.2.5/
This moment will nap, you will have a dream; But this moment study,you will interpret a dream.