CGLIB使用
what
CGLIB: 基于 ASM的字节码框架.
why
1.如果要代理的类为一个普通类、没有实现接口,只能使用CGLIB
.
2.CGLIB底层使用了ASM
.
demo
MyCommons/T01cglib
生成的cglib包下
PersonService$$EnhancerByCGLIB$$2d683b90$$FastClassByCGLIB$$8b3052f3.class
// cglib生成的代理类,继承了PersonService类
PersonService$$EnhancerByCGLIB$$2d683b90.class
PersonService$$FastClassByCGLIB$$edd83f4d.class
包结构
net.sf.cglib.beans
Java bean 相关的工具类
net.sf.cglib.core
底层字节码操作相关的类
大多数与 ASM 相关
net.sf.cglib.proxy
代理创建和方法拦截相关的类
net.sf.cglib.reflect
反射相关的类
net.sf.cglib.transform
编译和运行时, 类文件转换相关的类
net.sf.cglib.util
集合排序工具相关类
缓存
cglib 通过缓存已经生成的类, 提升效率.
生成类的缓存是按照 ClassLoader 来划分的.
AbstractClassGenerator 类
create()
模板方法, 定义生成类的过程
generateClass(ClassVisitor v)
子类实现, 用于生成所需的类
class name 生成策略
命名策略
class generator 必须继承 AbstractClassGenerator , 然后实现抽象方法 generateClass(),
generateClass 方法用来生成 class , class name 的生成也应该是在这个方法中.
在每个 generateClass 方法中, 当调用 ClassEmitter 的 begin_class 方法时都要求提供一个入参 class internal name.
这时会调用 AbstractClassGenerator 的 getClassName() 来生成一个可用的 class internal name.
final protected String getClassName() {
if (className == null)
className = getClassName(getClassLoader());
return className;
}
private String getClassName(final ClassLoader loader) {
final Set nameCache = getClassNameCache(loader);
return namingPolicy.getClassName(namePrefix, source.name, key, new Predicate() {
public boolean evaluate(Object arg) {
return nameCache.contains(arg);
}
});
}
private Set getClassNameCache(ClassLoader loader) {
return (Set)((Map)source.cache.get(loader)).get(NAME_KEY);
}
getClassName 首先根据 classloader 和 NAME_KEY 来获取已经生成的类名的列表.
命名策略是封装在 NamingPolicy 中的 getClassName 方法中的. 用户可以根据自己的实际需求通过实现接口 NamingPolicy 来定制命名策略.
Cglib 提供了一个默认的命名策略 DefaultNamingPolicy.DefaultNamingPolicy 同样实现了 NamingPolicy 接口.
这部分代码比较简单, 我们可以分析得出, 默认的命名策略为
被代理 class name + "$$" + class generator name + "ByCGLIB" + "$$" + key 的 hashcode
如果命名冲突的话, 会在上面产生的类名后面 + "_"+index(index>=2)
.
Class 生成策略
cglib 中生成类的工作是由 AbstractClassGenerator 的 create 方法使用相应的生成策略完成.
// 默认生成类的策略
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
byte[] b = strategy.generate(this);
GeneratorStrategy 是一个接口, 它负责调用 ClassGenerator 的 generateClass 方法来生成类.
DefaultGeneratorStrategy 是 cglib 提供的一个默认的生成策略.
public class DefaultGeneratorStrategy implements GeneratorStrategy {
public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy();
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = getClassVisitor();
transform(cg).generateClass(cw);
return transform(cw.toByteArray());
}
protected DebuggingClassWriter getClassVisitor() throws Exception {
return new DebuggingClassWriter(ClassWriter.COMPUTE_MAXS);
}
... ...
protected byte[] transform(byte[] b) throws Exception {
return b;
}
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
return cg;
}
}
DefaultGeneratorStrategy 实现了 ClassGenerator 接口, 并提供两个 transform 方法.
用户可以通过继承 DefaultGeneratorStrategy 并重写相关的方法来检查或者修改生成类.
类生成策略, 用户可以通过实现 GeneratorStrategy 接口来自定义生成策略, 并使用 AbstractClassGenerator 的 setStrategy 方法来设置自定义策略.
cglib 动态代理原理
cglib 动态代理 demo
- 创建 Enhancer 实例
- 通过 setSuperclass 方法来设置目标类
- 通过 setCallback 方法来设置拦截对象
4.create 方法生成 Target 的代理类, 并返回代理类的实例
// 1. 创建 Enhancer 实例
Enhancer enhancer = new Enhancer();
// 2. 将目标类设置为父类, 因为 cglib 基于父类 生成代理子类
enhancer.setSuperclass(PersonService.class);
// 3. 设置回调, 也就是我们的拦截处理
enhancer.setCallback(new CglibProxyInterceptor());
// 4. 创建代理类, 并返回代理类的实例
PersonService proxy = (PersonService) enhancer.create();
// 5. 调用代理类的方法
proxy.setPerson();
proxy.getPerson("1");
自定义拦截处理器如下:
public class CglibProxyInterceptor implements MethodInterceptor {
/**
* @param sub cglib 生成的代理对象
* @param method 被代理对象方法
* @param objects 方法入参
* @param methodProxy 代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前...");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("执行后...");
return object;
}
}
代理类
FastClass 机制
Jdk 动态代理的拦截对象是通过反射的机制来调用被拦截方法的, 反射的效率比较低.
cglib 采用了 FastClass 的机制来实现对被拦截方法的调用.
FastClass 机制就是对一个类的方法建立索引, 通过索引来直接调用相应的方法.