zoukankan      html  css  js  c++  java
  • cglib源码分析(一): 缓存和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));
        }
    }

    运行结果是:

    true
    20, {a, b}, hello
    false

          为了生成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:   return
    
    public 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:  areturn
    
    public 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:  return
    
    public 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:  ireturn
    
    public 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: ireturn
    
    public 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
  • 相关阅读:
    627. Swap Salary
    176. Second Highest Salary
    596. Classes More Than 5 Students
    183. Customers Who Never Order
    181. Employees Earning More Than Their Managers
    182. Duplicate Emails
    175. Combine Two Tables
    620. Not Boring Movies
    595. Big Countries
    HDU 6034 Balala Power! (贪心+坑题)
  • 原文地址:https://www.cnblogs.com/cruze/p/3843996.html
Copyright © 2011-2022 走看看