首页 > 代码库 > cglib源码分析1 ----- 缓存和KEY

cglib源码分析1 ----- 缓存和KEY

    cglib是一个java 字节码的生成工具,它是对asm的进一步封装,提供了一系列class generator。研究cglib主要是因为它也提供了动态代理功能,这点和jdk的动态代理类似。

一、 Cache的创建

    与jdk动态代理一样,cglib也提供了缓存来提高系统的性能,对于已经生成的类,直接使用而不必重复生成。这里不得不提到一个比较重要的抽象类AbstractClassGenerator,它采用了模版方法的设计模式,protected Object create(Object key) 就是模版方法,它定义了类生成的过程。AbstractClassGenerator只有一个构造函数protected AbstractClassGenerator(Source source),入参是一个Source类型的对象,Source是AbstractClassGenerator里面的一个静态内部类,Source有两个字段 name用来记录class generator,cache 就是缓存,它和jdk动态代理一样都是用了WeakHashMap,并且类型也是<ClassLoader,<Object,Class>>

    protected static class Source {        String name; //class generator的name,eg:如果使用Enhancer来生成增强类,name的值就为 net.sf.cglib.proxy. Enhancer        Map cache = new WeakHashMap();        public Source(String name) {            this.name = name;        }}

        每个class generator都必须继承AbstractClassGenerator并且实现 public void generateClass(ClassVisitor v) 方法用来生成所需要的类。每个class generator都有独立的缓存,比如 Enhancer 类中 private static final Source SOURCE = new Source(Enhancer.class.getName()); 在BeanGenerator 中 private static final Source SOURCE = new Source(BeanGenerator.class.getName()); 

二、 Cache的使用

    缓存的使用主要封装在AbstractClassGenerator的模版方法create中,下面是create方法的源码:

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 (useCache) {                     cache2.put(key, new WeakReference(gen));            }}

    生成类的缓存是按照ClassLoader来划分的,这是因为类的区分不仅根据类名还根据装载类的ClassLoader,也就是说同一个类被不同的ClassLoader加载,那么它们也是不同的,关于这部分内容可参考 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3 。每个ClassLoader的缓存中都会有一个NAME_KEY 这个主要是用来对生成的class name进行去重,NAME_KEY 会在生成类命名策略里有进一步的说明。此处还使用useCache 来标记是否使用缓存,这给了用户比较灵活的选择。

三、Key的例子

    每个生成类在缓存中都会有一个key与之相对应。对于那些只与单个类相关的生成类,可以采用类名作为key。在动态代理中生成类不仅与目标类相关,还与使用的拦截类(MethodInterceptor),过滤类(CallbackFilter)相关,这样的话就要使用multi-vaules key来标识这个生成类,在cglib中multi-vaules 也是动态生成的,KeyFactory  就是生成multi-vaules的工厂类,它是一个抽象类,也就是说它不能被实例化,但是它提供了一系列的静态工厂方法来生成multi-vaules的工厂类,这里很拗口,下面是cglib源码包中的一个例子:

package samples;import net.sf.cglib.core.KeyFactory;public class KeySample {    private interface MyFactory {        public Object newInstance(int a, char[] b, String d);    }    public static void main(String[] args) {        MyFactory f = (MyFactory)KeyFactory.create(MyFactory.class);        Object key1 = f.newInstance(20, new char[]{ ‘a‘, ‘b‘ }, "hello");        Object key2 = f.newInstance(20, new char[]{ ‘a‘, ‘b‘ }, "hello");        Object key3 = f.newInstance(20, new char[]{ ‘a‘, ‘_‘ }, "hello");        System.out.println(key1.equals(key2));        System.out.println(key1.toString());        System.out.println(key2.equals(key3));    }}

 

运行结果是:

true20, {a, b}, hellofalse

 

      为了生成multi-vaules 的工厂类,我们必须提供一个接口来描述multi-vaules的结构(上例中该接口为MyFactory),该接口有且只有一个方法newInstance,该方法的返回值必须为Object,该方法的入参可以是任意的对象,元数据类型 或者是任意维的数组 但是入参不能为空,如果为空就和默认的构造函数相冲突。 在分析KeyFactory之前,我们将上例生成的multi-vaules工厂类进行一下反编译(jd-gui 由于版本的问题无法反编译,因而此处使用javap):

public class samples.KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e extends net.sf.cglib.core.KeyFactory implements samples.KeySample$MyFactory{public samples.KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e();  Code:   0:   aload_0   1:   invokespecial   #11; //Method net/sf/cglib/core/KeyFactory."<init>":()V   4:   returnpublic java.lang.Object newInstance(int, char[], java.lang.String);  Code:   0:   new     #2; //class samples/KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e   3:   dup   4:   iload_1   5:   aload_2   6:   aload_3   7:   invokespecial   #16; //Method "<init>":(I[CLjava/lang/String;)V   10:  areturnpublic samples.KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e(int, char[], java.lang.String);  Code:   0:   aload_0   1:   invokespecial   #11; //Method net/sf/cglib/core/KeyFactory."<init>":()V   4:   aload_0   5:   dup   6:   iload_1   7:   putfield        #20; //Field FIELD_0:I   10:  dup   11:  aload_2   12:  putfield        #24; //Field FIELD_1:[C   15:  dup   16:  aload_3   17:  putfield        #28; //Field FIELD_2:Ljava/lang/String;   20:  returnpublic int hashCode();  Code:   0:   sipush  179   3:   aload_0   4:   getfield        #20; //Field FIELD_0:I   7:   swap   8:   ldc     #31; //int 467063   10:  imul   11:  swap   12:  iadd   13:  aload_0   14:  getfield        #24; //Field FIELD_1:[C   17:  dup   18:  ifnull  48   21:  astore_1   22:  iconst_0   23:  istore_2   24:  goto    39   27:  aload_1   28:  iload_2   29:  caload   30:  swap   31:  ldc     #31; //int 467063   33:  imul   34:  swap   35:  iadd   36:  iinc    2, 1   39:  iload_2   40:  aload_1   41:  arraylength   42:  if_icmplt       27   45:  goto    49   48:  pop   49:  aload_0   50:  getfield        #28; //Field FIELD_2:Ljava/lang/String;   53:  swap   54:  ldc     #31; //int 467063   56:  imul   57:  swap   58:  dup   59:  ifnull  68   62:  invokevirtual   #35; //Method java/lang/Object.hashCode:()I   65:  goto    70   68:  pop   69:  iconst_0   70:  iadd   71:  ireturnpublic boolean equals(java.lang.Object);  Code:   0:   aload_1   1:   instanceof      #2; //class samples/KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e   4:   ifeq    133   7:   aload_0   8:   getfield        #20; //Field FIELD_0:I   11:  aload_1   12:  checkcast       #2; //class samples/KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e   15:  getfield        #20; //Field FIELD_0:I   18:  if_icmpne       133   21:  aload_0   22:  getfield        #24; //Field FIELD_1:[C   25:  aload_1   26:  checkcast       #2; //class samples/KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e   29:  getfield        #24; //Field FIELD_1:[C   32:  dup2   33:  ifnonnull       43   36:  ifnonnull       49   39:  pop2   40:  goto    93   43:  ifnull  49   46:  goto    53   49:  pop2   50:  goto    133   53:  dup2   54:  arraylength   55:  swap   56:  arraylength   57:  if_icmpeq       64   60:  pop2   61:  goto    133   64:  astore_2   65:  astore_3   66:  iconst_0   67:  istore  4   69:  goto    86   72:  aload_2   73:  iload   4   75:  caload   76:  aload_3   77:  iload   4   79:  caload   80:  if_icmpne       133   83:  iinc    4, 1   86:  iload   4   88:  aload_2   89:  arraylength   90:  if_icmplt       72   93:  aload_0   94:  getfield        #28; //Field FIELD_2:Ljava/lang/String;   97:  aload_1   98:  checkcast       #2; //class samples/KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e   101: getfield        #28; //Field FIELD_2:Ljava/lang/String;   104: dup2   105: ifnonnull       115   108: ifnonnull       121   111: pop2   112: goto    131   115: ifnull  121   118: goto    125   121: pop2   122: goto    133   125: invokevirtual   #39; //Method java/lang/Object.equals:(Ljava/lang/Object;)Z   128: ifeq    133   131: iconst_1   132: ireturn   133: iconst_0   134: ireturnpublic java.lang.String toString();  Code:   0:   new     #43; //class java/lang/StringBuffer   3:   dup   4:   invokespecial   #44; //Method java/lang/StringBuffer."<init>":()V   7:   aload_0   8:   getfield        #20; //Field FIELD_0:I   11:  invokevirtual   #48; //Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;   14:  goto    23   17:  pop   18:  ldc     #50; //String null   20:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   23:  ldc     #55; //String ,   25:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   28:  aload_0   29:  getfield        #24; //Field FIELD_1:[C   32:  dup   33:  ifnull  96   36:  swap   37:  ldc     #57; //String {   39:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   42:  swap   43:  astore_1   44:  iconst_0   45:  istore_2   46:  goto    72   49:  aload_1   50:  iload_2   51:  caload   52:  invokevirtual   #60; //Method java/lang/StringBuffer.append:(C)Ljava/lang/StringBuffer;   55:  goto    64   58:  pop   59:  ldc     #50; //String null   61:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   64:  ldc     #55; //String ,   66:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   69:  iinc    2, 1   72:  iload_2   73:  aload_1   74:  arraylength   75:  if_icmplt       49   78:  dup   79:  dup   80:  invokevirtual   #63; //Method java/lang/StringBuffer.length:()I   83:  iconst_2   84:  isub   85:  invokevirtual   #67; //Method java/lang/StringBuffer.setLength:(I)V   88:  ldc     #69; //String }   90:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   93:  goto    102   96:  pop   97:  ldc     #50; //String null   99:  invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   102: ldc     #55; //String ,   104: invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   107: aload_0   108: getfield        #28; //Field FIELD_2:Ljava/lang/String;   111: dup   112: ifnull  124   115: invokevirtual   #71; //Method java/lang/Object.toString:()Ljava/lang/String;   118: invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   121: goto    130   124: pop   125: ldc     #50; //String null   127: invokevirtual   #53; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;   130: invokevirtual   #72; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;   133: areturn}
View Code

 

从反编译的结果我们可以看出,生成的工厂类为samples.KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e,它继承了net.sf.cglib.core.KeyFactory 类,实现了samples.KeySample$MyFactory接口,同时也实现了工厂方法newInstance,所以上例中key1,key2,key3都是通过该工厂方法产生了key的对象。samples.KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e 中有两个构造函数,一个是默认的构造函数(由于工厂方法newInstance 为非静态方法,所以需要使用默认构造函数来生成第一个对象),另外一个构造函数的入参和 newInstance 入参一样,newInstance使用有参构造函数来生成multi-values key 对象。samples.KeySample$MyFactory$$KeyFactoryByCGLIB$$7116a61e 为newInstance的每一个入参都生成了一个相同类型的field用来存储key的value。除此之外还提供了三个方法:hashCode, equals, toString.

hashCode 和 equals 在HashMap 的get方法中用于和存储的key进行比较,所以这两个方法是比较重要的。

四、KeyFactory 源码分析

KeyFactory的源码还是比较多的,接下来只对其中的关键代码进行分析:

        public void generateClass(ClassVisitor v) {            ClassEmitter ce = new ClassEmitter(v);            //对定义key工厂类结构的接口进行判断,判断该接口是否只有newInstance一个方法,newInstance的返回值是否为Object            Method newInstance = ReflectUtils.findNewInstance(keyInterface);            if (!newInstance.getReturnType().equals(Object.class)) {                throw new IllegalArgumentException("newInstance method must return Object");            }            //获取newInstance的入参类型,此处使用ASM的Type来定义            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);                        //生成newInstance 工厂方法            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();                        //生成hashCode            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函数,在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();        }
View Code