什么是Cglib
Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了ASM操作,实现了运行期生成新的class。
运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。
Cglib优缺点
优点:
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
JDK动态代理要求被代理的类必须实现接口,当需要代理的类没有实现接口时Cglib代理是一个很好的选择。另一个优点是Cglib动态代理比使用java反射的JDK动态代理要快(Cglib的FastClass机制,解析参考http://www.cnblogs.com/cruze/category/593899.html)
缺点:
对于被代理类中的final方法,无法进行代理,因为子类中无法重写final函数
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理
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相关的工具类
package com.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.core.DefaultGeneratorStrategy;
import net.sf.cglib.core.GeneratorStrategy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* MyMethodInterceptor 用来实现提供给代理对象调用的方法。
* @author gaohaicheng
*
*/
public class MyMethodInterceptor implements MethodInterceptor {
/**
* 从源码可以看出,这个接口只有一个方法——intercept,这个方法有4个参数,分别是增强的对象,即实 现这个接口类的一个对象;
* method表示要被拦截的方法; args要被拦截方法的参数;proxy表示要触发父类的方法对象;
*/
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
System.out.println("准备开始 :" + method);
Object object = proxy.invokeSuper(obj, arg);
System.out.println("已经结束了 :" + method);
return object;
}
public static void main(String[] args) throws Exception {
//Enhancer是Cglib代理的核心类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Programer.class);
enhancer.setCallback(new MyMethodInterceptor());
Programer programer = (Programer)enhancer.create();
//开始调用
programer.eat("代码级大餐");
System.out.println("------------------------------------------------------------------");
programer.wear();
}
}
//**************************************被代理类*************************************
/**
* person
* @author gfw2306
*
*/
class Programer {
public void wear(){
System.out.println("穿衣服");
}
public void eat(String food) {
// TODO Auto-generated method stub
System.out.println("程序猿大餐开吃,妈的");
}
}
想看一下cglib生成的class文件是什么样的就要用到一个工具:HSDB
借HSDB来探索HotSpot VM的运行时数据.
1、在cmd中执行,当然先跳到jdk的bin目录下执行。
H:\Program Files\Java\jdk1.7.0_79\bin>Java -classpath “%JAVA_HOME%/lib/sa-jdi.jar” sun.jvm.hotspot.HSDB
执行完指令后
2、会出现HSDB窗口
然后查找执行中生成的动态代理类:
点击生成:
最后会在jdk下生成和你包名相同的路径下的class类:
使用jad反编译工具编译出class文件:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: <generated>
package com.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.*;
// Referenced classes of package com.cglib:
// Programer
public class Programer$$EnhancerByCGLIB$$e950f55f extends Programer
implements Factory
{
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$2$Method;
CGLIB$emptyArgs;
CGLIB$finalize$2$Proxy;
intercept();
return;
super.finalize();
return;
}
public final boolean equals(Object obj)
{
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 57;
goto _L3 _L4
_L3:
this;
CGLIB$equals$3$Method;
new Object[] {
obj
};
CGLIB$equals$3$Proxy;
intercept();
JVM INSTR dup ;
JVM INSTR ifnonnull 50;
goto _L5 _L6
_L5:
JVM INSTR pop ;
false;
goto _L7
_L6:
(Boolean);
booleanValue();
_L7:
return;
_L4:
return super.equals(obj);
}
public final String toString()
{
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 40;
goto _L3 _L4
_L3:
this;
CGLIB$toString$4$Method;
CGLIB$emptyArgs;
CGLIB$toString$4$Proxy;
intercept();
(String);
return;
_L4:
return super.toString();
}
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 _L5 _L6
_L5:
JVM INSTR pop ;
0;
goto _L7
_L6:
(Number);
intValue();
_L7:
return;
_L4:
return super.hashCode();
}
protected final Object clone()
throws CloneNotSupportedException
{
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:
this;
CGLIB$clone$6$Method;
CGLIB$emptyArgs;
CGLIB$clone$6$Proxy;
intercept();
return;
_L4:
return super.clone();
}
public Object newInstance(Class aclass[], Object aobj[], Callback acallback[])
{
CGLIB$SET_THREAD_CALLBACKS(acallback);
JVM INSTR new #2 <Class Programer$$EnhancerByCGLIB$$e950f55f>;
JVM INSTR dup ;
aclass;
aclass.length;
JVM INSTR tableswitch 0 0: default 35
// 0 28;
goto _L1 _L2
_L2:
JVM INSTR pop ;
Programer$$EnhancerByCGLIB$$e950f55f();
goto _L3
_L1:
JVM INSTR pop ;
throw new IllegalArgumentException("Constructor not found");
_L3:
CGLIB$SET_THREAD_CALLBACKS(null);
return;
}
public Object newInstance(Callback acallback[])
{
CGLIB$SET_THREAD_CALLBACKS(acallback);
CGLIB$SET_THREAD_CALLBACKS(null);
return new Programer$$EnhancerByCGLIB$$e950f55f();
}
public Object newInstance(Callback callback)
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] {
callback
});
CGLIB$SET_THREAD_CALLBACKS(null);
return new Programer$$EnhancerByCGLIB$$e950f55f();
}
public void setCallback(int i, Callback callback)
{
switch(i)
{
case 0: // '\0'
CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
break;
}
}
public final void eat(String s)
{
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 42;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_42;
this;
CGLIB$eat$0$Method;
new Object[] {
s
};
CGLIB$eat$0$Proxy;
intercept();
return;
super.eat(s);
return;
}
public final void wear()
{
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$wear$1$Method;
CGLIB$emptyArgs;
CGLIB$wear$1$Proxy;
intercept();
return;
super.wear();
return;
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback acallback[])
{
CGLIB$THREAD_CALLBACKS.set(acallback);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback acallback[])
{
CGLIB$STATIC_CALLBACKS = acallback;
}
public static MethodProxy CGLIB$findMethodProxy(Signature signature)
{
String s = signature.toString();
s;
s.hashCode();
JVM INSTR lookupswitch 7: default 160
// -1574182249: 76
// -508378822: 88
// 685027751: 100
// 1223317398: 112
// 1826985398: 124
// 1913648695: 136
// 1984935277: 148;
goto _L1 _L2 _L3 _L4 _L5 _L6 _L7 _L8
_L2:
"finalize()V";
equals();
JVM INSTR ifeq 161;
goto _L9 _L10
_L10:
break MISSING_BLOCK_LABEL_161;
_L9:
return CGLIB$finalize$2$Proxy;
_L3:
"clone()Ljava/lang/Object;";
equals();
JVM INSTR ifeq 161;
goto _L11 _L12
_L12:
break MISSING_BLOCK_LABEL_161;
_L11:
return CGLIB$clone$6$Proxy;
_L4:
"eat(Ljava/lang/String;)V";
equals();
JVM INSTR ifeq 161;
goto _L13 _L14
_L14:
break MISSING_BLOCK_LABEL_161;
_L13:
return CGLIB$eat$0$Proxy;
_L5:
"wear()V";
equals();
JVM INSTR ifeq 161;
goto _L15 _L16
_L16:
break MISSING_BLOCK_LABEL_161;
_L15:
return CGLIB$wear$1$Proxy;
_L6:
"equals(Ljava/lang/Object;)Z";
equals();
JVM INSTR ifeq 161;
goto _L17 _L18
_L18:
break MISSING_BLOCK_LABEL_161;
_L17:
return CGLIB$equals$3$Proxy;
_L7:
"toString()Ljava/lang/String;";
equals();
JVM INSTR ifeq 161;
goto _L19 _L20
_L20:
break MISSING_BLOCK_LABEL_161;
_L19:
return CGLIB$toString$4$Proxy;
_L8:
"hashCode()I";
equals();
JVM INSTR ifeq 161;
goto _L21 _L22
_L22:
break MISSING_BLOCK_LABEL_161;
_L21:
return CGLIB$hashCode$5$Proxy;
_L1:
JVM INSTR pop ;
return null;
}
public void setCallbacks(Callback acallback[])
{
this;
acallback;
JVM INSTR dup2 ;
0;
JVM INSTR aaload ;
(MethodInterceptor);
CGLIB$CALLBACK_0;
}
public Callback[] getCallbacks()
{
CGLIB$BIND_CALLBACKS(this);
this;
return (new Callback[] {
CGLIB$CALLBACK_0
});
}
public Callback getCallback(int i)
{
CGLIB$BIND_CALLBACKS(this);
this;
i;
JVM INSTR tableswitch 0 0: default 30
// 0 24;
goto _L1 _L2
_L2:
CGLIB$CALLBACK_0;
goto _L3
_L1:
JVM INSTR pop ;
null;
_L3:
return;
}
final void CGLIB$eat$0(String s)
{
super.eat(s);
}
final void CGLIB$wear$1()
{
super.wear();
}
final Object CGLIB$clone$6()
throws CloneNotSupportedException
{
return super.clone();
}
final boolean CGLIB$equals$3(Object obj)
{
return super.equals(obj);
}
final void CGLIB$finalize$2()
throws Throwable
{
super.finalize();
}
final String CGLIB$toString$4()
{
return super.toString();
}
final int CGLIB$hashCode$5()
{
return super.hashCode();
}
static void CGLIB$STATICHOOK1()
{
Method amethod[];
Method amethod1[];
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class class1 = Class.forName("com.cglib.Programer$$EnhancerByCGLIB$$e950f55f");
Class class2;
amethod = ReflectUtils.findMethods(new String[] {
"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"
}, (class2 = Class.forName("java.lang.Object")).getDeclaredMethods());
Method[] _tmp = amethod;
CGLIB$finalize$2$Method = amethod[0];
CGLIB$finalize$2$Proxy = MethodProxy.create(class2, class1, "()V", "finalize", "CGLIB$finalize$2");
CGLIB$equals$3$Method = amethod[1];
CGLIB$equals$3$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
CGLIB$toString$4$Method = amethod[2];
CGLIB$toString$4$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
CGLIB$hashCode$5$Method = amethod[3];
CGLIB$hashCode$5$Proxy = MethodProxy.create(class2, class1, "()I", "hashCode", "CGLIB$hashCode$5");
CGLIB$clone$6$Method = amethod[4];
CGLIB$clone$6$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
amethod1 = ReflectUtils.findMethods(new String[] {
"eat", "(Ljava/lang/String;)V", "wear", "()V"
}, (class2 = Class.forName("com.cglib.Programer")).getDeclaredMethods());
Method[] _tmp1 = amethod1;
CGLIB$eat$0$Method = amethod1[0];
CGLIB$eat$0$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/String;)V", "eat", "CGLIB$eat$0");
CGLIB$wear$1$Method = amethod1[1];
CGLIB$wear$1$Proxy = MethodProxy.create(class2, class1, "()V", "wear", "CGLIB$wear$1");
}
private static final void CGLIB$BIND_CALLBACKS(Object obj)
{
Programer$$EnhancerByCGLIB$$e950f55f programer$$enhancerbycglib$$e950f55f = (Programer$$EnhancerByCGLIB$$e950f55f)obj;
if(programer$$enhancerbycglib$$e950f55f.CGLIB$BOUND) goto _L2; else goto _L1
_L1:
Object obj1;
programer$$enhancerbycglib$$e950f55f.CGLIB$BOUND = true;
obj1 = CGLIB$THREAD_CALLBACKS.get();
obj1;
if(obj1 != null) goto _L4; else goto _L3
_L3:
JVM INSTR pop ;
CGLIB$STATIC_CALLBACKS;
if(CGLIB$STATIC_CALLBACKS != null) goto _L4; else goto _L5
_L5:
JVM INSTR pop ;
goto _L2
_L4:
(Callback[]);
programer$$enhancerbycglib$$e950f55f;
JVM INSTR swap ;
0;
JVM INSTR aaload ;
(MethodInterceptor);
CGLIB$CALLBACK_0;
_L2:
}
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback CGLIB$STATIC_CALLBACKS[];
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$eat$0$Method;
private static final MethodProxy CGLIB$eat$0$Proxy;
private static final Object CGLIB$emptyArgs[];
private static final Method CGLIB$wear$1$Method;
private static final MethodProxy CGLIB$wear$1$Proxy;
private static final Method CGLIB$finalize$2$Method;
private static final MethodProxy CGLIB$finalize$2$Proxy;
private static final Method CGLIB$equals$3$Method;
private static final MethodProxy CGLIB$equals$3$Proxy;
private static final Method CGLIB$toString$4$Method;
private static final MethodProxy CGLIB$toString$4$Proxy;
private static final Method CGLIB$hashCode$5$Method;
private static final MethodProxy CGLIB$hashCode$5$Proxy;
private static final Method CGLIB$clone$6$Method;
private static final MethodProxy CGLIB$clone$6$Proxy;
static
{
CGLIB$STATICHOOK1();
}
public Programer$$EnhancerByCGLIB$$e950f55f()
{
CGLIB$BIND_CALLBACKS(this);
}
}