CGLIB生存的Class的命名规则有多种,它们都是由接口NamingPolicy对应的实现来定义的.接下来针对DefaultNamingPolicy进行分析.泛泛的说,生成的CLASS的规则如下
被代理class name(包名和类名) + "$$" +
使用cglib处理的class name(只有类名,不包含包名) +"ByCGLIB" + "$$" +
key的hashcode(接下来会对key有一个详细的分析) +
序列号
下面是上面规则的示例:
aop.target.HelloImpl$$EnhancerByCGLIB$$494b5b61
aop.target.HelloImpl$$EnhancerByCGLIB$$494b5b61_2
aop.target.HelloImpl$$EnhancerByCGLIB$$494b5b61_3
下面是对应的关键代码
#DefaultNamingPolicy
public String getClassName(String prefix, String source, Object key, Predicate names) {
StringBuffer sb = new StringBuffer();
sb.append(
(prefix != null) ?
(
prefix.startsWith("java") ?
"$" + prefix : prefix
)
: "net.sf.cglib.empty.Object"
);
sb.append("$$");
sb.append(source.substring(source.lastIndexOf('.') + 1));
sb.append("ByCGLIB$$");
sb.append(Integer.toHexString(key.hashCode()));
String base = sb.toString();
String attempt = base;
int index = 2;
while (names.evaluate(attempt)) {
attempt = base + "_" + index++;
}
return attempt;
}
Key 是什么?
上面的生成规则有4个参数,其中key是一个不太好理解的参数
Key是一个对象,该对象封装了下面7个信息. 并且这个Key对象是由Cglib生成的一个类来创建出来的.
1:superclass
2:interfaces
3:filter
4:callbackTypes
5:serialVersionUID
6:useFactory,
7:interceptDuringConstruction
下面的代码是生成key的接口定义,以及Cglib如何生成此接口的实例
//Enhancer.EnhancerKey
public interface EnhancerKey {
public Object newInstance(String type,
String[] interfaces,
CallbackFilter filter,
Type[] callbackTypes,
boolean useFactory,
boolean interceptDuringConstruction,
Long serialVersionUID);
}
//Enhancer Cglib会动态生成一个接口(EnhancerKey)的字节码并实例化,接下来将试用此对象生成Key来封装上面提到的几个参数
private static final EnhancerKey KEY_FACTORY =
(EnhancerKey)KeyFactory.create(EnhancerKey.class);
为什么有序列号的存在?
通常默认情况是,相同的Classload,相同的key只生成一个只生成一次子类并缓存,也就是在DefaultNamingPolicy,没有发现有序列号存在的可能. 序列号应该是在别的场景中使用. 下面是生成的子类是如何通过HashSet缓存起来的:
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) {
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
//添加Classname到Cache里面, Cache实际上是一个HashSet的实例
getClassNameCache(loader).add(className);
gen = ReflectUtils.defineClass(className, b, loader);
}
if (useCache) {
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);
}
}
接下来准备,继续写一个博文介绍下面3点
1)Cglib如何生成的Class的二进制文件
2)Cglib生成的Class二进制(byte[])放哪
3)Cglib如何把二进制Load生成的Class