作用:
Generates classes to handle multi-valued keys, for use in things such as Maps and Sets. Code for equals and hashCode methods follow the the rules laid out in Effective Java by Joshua Bloch.
什么叫multi-valued keys
就是有多个键的组合,一起作为一个Key
比如[a b c]是一个组合,一起作为key,[2 3]也可以是作为key
KeyFactory就是用来生成这样一组"Key"的
通过两组的equals,hashCode等方法判断是否为同一组key的场景
要求:
To generate a KeyFactory, you need to supply an interface which describes the structure of the key. The interface should have a single method named newInstance, which returns an Object. The arguments array can be anything--Objects, primitive values, or single or multi-dimension arrays of either.
为了描述Key的组合,需要定义一个接口,仅提供一个方法,叫做newInstance,且返回值为Object,这个是要求
demo
参照自带的demo,位于cglib包下面samples.KeySample,自己略有改动
package samples;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.core.KeyFactory;
public class KeySample {
private interface MyFactory {
public Object newInstance(int a, int b);
}
public static void main(String[] args) {
//这一句是把class文件输出在指定目录
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, ".//");
MyFactory f = (MyFactory)KeyFactory.create(MyFactory.class);
MyFactory f1 = (MyFactory)KeyFactory.create(MyFactory.class);
System.out.println(f == f1);//false
System.out.println(f.equals(f1));//true
Object key1 = f.newInstance(20, 30);
Object key2 = f.newInstance(20, 30);
Object key3 = f.newInstance(20, 40);
System.out.println(key1.equals(key2));//true
System.out.println(key2.equals(key3));//false
}
}
可以看出
1.f和f1的关系,这实际上是用了缓存,缓存了同样的类对象,只不过生成不同的实例
2.key1和key2这个组合,是一样的,这是利用KeyFactory实现了equals和hash的方法
这样使得这种组合的Key能够用在map和set中
实现原理
demo中根据要求,拿到我们组合Key的对象是在
MyFactory f = (MyFactory)KeyFactory.create(MyFactory.class);
跟进去就是
net.sf.cglib.core.KeyFactory#create(java.lang.ClassLoader, java.lang.Class, net.sf.cglib.core.Customizer)
net.sf.cglib.core.KeyFactory.Generator#create
net.sf.cglib.core.AbstractClassGenerator#create
这里涉及到AbstractClassGenerator,这个是cglib中进行code-generating的工具类
看实现
protected Object create(Object key) {
try {
//需要缓存的类
Class gen = null;
synchronized (source) {
ClassLoader loader = getClassLoader();
Map cache2 = null;
//根据来源区分,根据classLoader进行一级缓存
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));
getClassNameCache(loader).add(className);
//根据字节码生成类
gen = ReflectUtils.defineClass(className, b, loader);
}
if (useCache) {
//根据传入的key,进行二级缓存
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);
}
}
说明:
1.缓存策略和之前讲动态代理的缓存比较
都用了二级缓存,一级为classLoader,二级为对应的interfaces
这里的source.cache是weakHashMap
这里的二级缓存的value是new WeakReference(gen),也是WeakReference
2.这里cglib的字节码生成
byte[] b = strategy.generate(this);
会用到默认实现,net.sf.cglib.core.DefaultGeneratorStrategy#generate
根据传入的ClassGenerator进行对应调用
这里实现在net.sf.cglib.core.KeyFactory.Generator#generateClass里面
主要是利用了asm,生成了asm文件一级class文件
public void generateClass(ClassVisitor v) {
ClassEmitter ce = new ClassEmitter(v);
Method newInstance = ReflectUtils.findNewInstance(keyInterface);
if (!newInstance.getReturnType().equals(Object.class)) {
throw new IllegalArgumentException("newInstance method must return Object");
}
Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
ce.begin_class(Constants.V1_2,
Constants.ACC_PUBLIC,
getClassName(),
KEY_FACTORY,
new Type[]{ Type.getType(keyInterface) },
Constants.SOURCE_FILE);
EmitUtils.null_constructor(ce);
EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
int seed = 0;
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
TypeUtils.parseConstructor(parameterTypes),
null);
e.load_this();
e.super_invoke_constructor();
e.load_this();
for (int i = 0; i < parameterTypes.length; i++) {
seed += parameterTypes[i].hashCode();
ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
getFieldName(i),
parameterTypes[i],
null);
e.dup();
e.load_arg(i);
e.putfield(getFieldName(i));
}
e.return_value();
e.end_method();
// hash code
e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)];
int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)];
e.push(hc);
for (int i = 0; i < parameterTypes.length; i++) {
e.load_this();
e.getfield(getFieldName(i));
EmitUtils.hash_code(e, parameterTypes[i], hm, customizer);
}
e.return_value();
e.end_method();
// equals
e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
Label fail = e.make_label();
e.load_arg(0);
e.instance_of_this();
e.if_jump(e.EQ, fail);
for (int i = 0; i < parameterTypes.length; i++) {
e.load_this();
e.getfield(getFieldName(i));
e.load_arg(0);
e.checkcast_this();
e.getfield(getFieldName(i));
EmitUtils.not_equals(e, parameterTypes[i], fail, customizer);
}
e.push(1);
e.return_value();
e.mark(fail);
e.push(0);
e.return_value();
e.end_method();
// toString
e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
e.new_instance(Constants.TYPE_STRING_BUFFER);
e.dup();
e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
for (int i = 0; i < parameterTypes.length; i++) {
if (i > 0) {
e.push(", ");
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
}
e.load_this();
e.getfield(getFieldName(i));
EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizer);
}
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
e.return_value();
e.end_method();
ce.end_class();
}
可以看出来利用asm完成了这个类的hashCode以及equals方法
可以看到,equals方法其实就是判断两个类对象(KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e)的参数类型是否一致以及值是否相等
*** 3.equals方法这段代码是怎么generate出来的 ***
这一段是由asm中这段代码生成的
// equals
e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
Label fail = e.make_label();
e.load_arg(0);
//目标对象是同类型
e.instance_of_this();
e.if_jump(e.EQ, fail);
for (int i = 0; i < parameterTypes.length; i++) {
e.load_this();
e.getfield(getFieldName(i));
e.load_arg(0);
//cast操作
e.checkcast_this();
e.getfield(getFieldName(i));
//每个字段都equals
EmitUtils.not_equals(e, parameterTypes[i], fail, customizer);
}
e.push(1);
e.return_value();
e.mark(fail);
e.push(0);
e.return_value();
e.end_method();
上面这一段可以大概理解asm里面是如何处理equals操作的
不具体展开asm的调用过程,只要知道整个class文件都是net.sf.cglib.core.KeyFactory.Generator#generateClass生成
然后在net.sf.cglib.core.DefaultGeneratorStrategy#generate转换成字节码的
思考
使用场景
需要多个键联合一起组成一个key的
参照samples.KeySample
这些Key组合的具体类型是什么,每次运行都不同
根据KeyFactory生成类文件,这里就是KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e
生成类文件的过程
具体生成基本在net.sf.cglib.core.AbstractClassGenerator#create,依然用了二级缓存,reference
equals方法时如何generate的
asm
这里KeyFactory只是用来生成联合Key的,中间调用了AbstractClassGenerator生成类,但是这个类本身对于cglib有什么用?
在后面,根据一堆配置生成一个代理类的时候,结合缓存,就有用武之地了,配置中每一项组合成一个Key
在后面的demo以及源码解析会讲到
refer
http://cglib.sourceforge.net/apidocs/
http://www.cnblogs.com/cruze/p/3843996.html