上一篇博文: CGLIB学习札记---生成CLASS的命名规则 介绍了生成之类的命名规则, 在这个博文里面主要分析了下面3点:
1)Cglib如何生成的Class的二进制文件
2)Cglib生成的Class二进制(byte[])放哪
3)Cglib如何把二进制Load生成的Class
泛泛而谈,整个过程如下
- 就是Cglib根据父类,Callback, Filter 及一些相关信息生成key.
- 然后根据key 生成对应的子类的二进制表现形式
- 使用ClassLoader装载对应的二进制,生成Class对象,并缓存
- 最后实例化Class对象,并缓存
下面是相对应的关键代码.
1)Cglib如何生成的Class的二进制文件
针对不同场景, CGlib准备了不同的Class生成方法, 他们都实现了接口: ClassGenerator. 下面我们只针对默认的Enhancer来分析.
//此函数会被AbstractClassGenerator.create间接调用,并会在create函数中将结果缓存.
Enhancer.generateClass(ClassVisitor v)
//AbstractClassGenerator.create(Object key)
protected Object create(Object key) {
try {
Class gen = null;
synchronized (source) {
ClassLoader loader = getClassLoader();
Map cache2 = null;
cache2 = (Map)source.cache.get(loader);
if (cache2 == null) {
cache2 = new HashMap();
cache2.put(NAME_KEY, new HashSet());
source.cache.put(loader, cache2);
} else if (useCache) {
Reference ref = (Reference)cache2.get(key);
gen = (Class) (( ref == null ) ? null : ref.get());
}
if (gen == null) {
Object save = CURRENT.get();
CURRENT.set(this);
try {
this.key = key;
if (attemptLoad) {
try {
gen = loader.loadClass(getClassName());
} catch (ClassNotFoundException e) {
// ignore
}
}
if (gen == null) {
//生成的Class的二进制存储
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
//将类名放入Cache中,Cache实际上是一个Hashset的实例
getClassNameCache(loader).add(className);
//将生成的类装载路JVM
gen = ReflectUtils.defineClass(className, b, loader);
}
if (useCache) {
//将装载的类放入cache
cache2.put(key, new WeakReference(gen));
}
return firstInstance(gen);
} finally {
CURRENT.set(save);
}
}
}
return firstInstance(gen);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
2)Cglib生成的Class二进制(byte[])放哪
放在byte数组中,下面这行代码就截取于方法AbstractClassGenerator.create(Object key)
byte[] b = strategy.generate(this);
然后通过 ReflectUtils.defineClass(className, b, loader) 生成对应的Class实例,并缓存入cache2
3)Cglib如何把二进制Load生成的Class
//ReflectUtils.defineClass(className, b, loader)
public static Class defineClass(String className, byte[] b, ClassLoader loader) throws Exception {
Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), PROTECTION_DOMAIN };
//DEFINE_CLASS 是通过静态块来实例化的一个java.lang.ClassLoader.defineClass的方法对象
Class c = (Class)DEFINE_CLASS.invoke(loader, args);
// Force static initializers to run.
Class.forName(className, true, loader);
return c;
}