CGLIB原理简析-后篇

在前面的文章(CGLIB原理简析-前篇)中,我们已经弄清楚了代理对象使用相关代理逻辑,本篇文章将逐步揭开代理类生成及实例化的过程。

一、Enhancer-增强

在大部分场景下,我们使用CGLIB获取动态代理对象的基本代码如下:

MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Student.class);
enhancer.setCallback(myMethodInterceptor);
Student stu = (Student) enhancer.create();
stu.outStudentName();

可以看到,Enhancer就是创建代理对象的关键类型。因此,本文第一章节主要分析Enhancer的构成和功能。为了对Enhancer类有个大概的印象,下面先给出Enhancer源码注释【翻译】:

  1. Enhancer会生成能够实现方法拦截的动态子类。Enhancer类最初是为了作为JDK Proxy代理的替代方案,但是Enhancer能够代理具体实现类,而不仅仅是实现接口。生成的子类会重写所有被代理类非final方法,并且使用者可以自定义方法拦截器实现方法拦截。
  2. 其中,最原始、最常用的回调对象类型是MethodInterceptor。在切面(AOP)领域中,MethodInterceptor能够实现环绕通知的能力。基于环绕通知能力,你可以在调用被代理方法的前后穿插执行自定义行为。不仅如此,你也可以改变方法的入参数值,甚至根本不调用被代理方法。
  3. 尽管MethodInterceptor已经足够通用且能满足任何代理的需要,回调对象还有其他可用类型,比如LazyLoader,目的是为了更加简化或具备更好的性能。常常一个增强子类只会使用一个回调对象,但是你也可以通过CallbackFilter来控制不同方法使用不同回调对象。
  4. 在CGLIB包下很多类都有类似设计。这些类会提供一些静态方法提供给外界使用,但是为了更好的控制对象,比如控制Enhancer生成子类的自定义类加载器,就需要使用Enhancer的构造器。
  5. 所有的Enhancer生成的增强子类都会实现Factory接口,当然你也可以通过setUseFactory方法使得子类不实现Factory接口。Factory提供了一些API,可用于修改代理对象的回调对象,也提供了更快、更容易的方式生成一个代理对象。

1.1 Enhancer类间关系

不着急,我们先来看下Enhancer的类间关系:

public class Enhancer extends AbstractClassGenerator
...
}

Enhancer类仅继承一个抽象类AbstractClassGenerator。AbstractClassGenerator抽象类在cglib包下处于十分关键的位置,几乎任何动态生成字节码的功能类都继承该抽象类,Enhancer仅仅是一个用于生成动态增强子类信息的AbstractClassGenerator具体实现子类,有关AbstractClassGenerator本节第二章会详细叙述。
从类间关系上&功能看,Enhancer类职责实际上是运行时动态生成增强子类字节码的类。这个概念我认为十分重要,不要一股脑扎进“代理”概念中,Enhancer(或者我们说的cglib代理)更切合的理解是“增强

1.2 Enhancer对象属性

Enhancer类的属性十分多,这里仅列出与增强子类相关的对象属性,而ASM生成字节码相关的静态类变量在类加载时就初始化了,不涉及复杂逻辑。

private Class[] interfaces;			// 增强子类实现的接口列表
private CallbackFilter filter;		// 根据filter根据方法选择不同回调对象
private Callback[] callbacks;		// 回调对象列表
private Type[] callbackTypes;		// 回调对象类型列表
private boolean validateCallbackTypes;	// 是否已确定回调对象类型列表标识
private boolean classOnly;				// 是否仅返回Class对象,而不是实例化对象
private Class superclass;			// 增强子类继承的父类	
private Class[] argumentTypes;		// 父类构造器类型列表
private Object[] arguments;			// 父类构造器入参值
private boolean useFactory = true;	// 增强子类是否实现Factory接口
private Long serialVersionUID;		// 是否支持序列化操作
private boolean interceptDuringConstruction = true;	// 是否拦截构造方法

1.3 Enhancer生成增强子类静态方法

增强子类的生成依靠Enhancer对象的能力。根据Enhancer类源码注释,Enhancer提供了多个静态方法供外界使用:

  • public static Object create(Class type, Callback callback)
    根据父类类型、回调对象创建增强子类对象。
  • public static Object create(Class superclass, Class interfaces[], Callback callback)
    根据父类类型、接口列表、回调对象创建增强子类对象。
  • public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks)
    根据父类类型、接口列表、回调对象过滤器、回调对象列表创建增强子类对象。

这三个静态方法逻辑类似,实际上无非是封装了Enhancer对象的创建、属性赋值、创建增强子类对象的过程。下面为最后一个静态方法代码:

public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
    Enhancer e = new Enhancer();	// Enhancer仅有的无参构造方法
    e.setSuperclass(superclass);	// 设置各个入参
    e.setInterfaces(interfaces);
    e.setCallbackFilter(filter);
    e.setCallbacks(callbacks);
    return e.create();				// 创建并返回增强子类对象
}

在前面一个小节,Enhancer对象的属性其实不止这些,因此如果需要对增强代理对象进行其他控制,比如不实现Factory方法,我们就不能使用这些封装后的static方法,就需要手动创建Enhancer对象。

Enhancer e = new Enhancer();	// Enhancer仅有的无参构造方法
e.setSuperclass(type);
e.setCallback(callback);
e.setSerialVersionUID(1111000L);
e.setUseFactory(false);			// 设置不实现Factory接口
return e.create();				// 创建并返回增强子类对象

另外,静态方法只能实现对无参构造的父类进行创建增强子类。如果父类为有参构造,就必须使用带入参的create方法。

Enhancer e= new Enhancer();
e.setSuperclass(Employee.class);
e.setCallbacks(new Callback[]{myMethodInterceptor, anotherMethodInterceptor});
e.setCallbackFilter(new MyCallbackFilter());
return e.create(new Class[]{String.class}, new Object[]{"spl"});

不论是使用静态方法,还是自行创建控制创建流程,最后都会调用Enhancer#create(…)创建增强子类对象。

1.4 增强子类的创建过程

Enhancer对象提供了三个创建create方法:

  1. public Object create()
    无参构造,创建增强子类实例对象;
    classOnly=false,argumentTypes = null;
  2. public Object create(Class[] argumentTypes, Object[] arguments)
    有参构造,创建增强子类实例对象
    classOnly=false
  3. public Class createClass()
    无参构造,创建增强子类Class对象
    classOnly=true
    具体create方法逻辑十分简单,就是设置了几个属性标识,实际创建增强子类逻辑在createHelper()方法中,我们直接来看这个方法:
private Object createHelper() {
    preValidate();	// 前置校验
    // 通过KeyFactory机制根据父类、接口等关键特征生成Key,这个也是后续作为缓存得Key.
    Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
            ReflectUtils.getNames(interfaces),
            filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
            callbackTypes,
            useFactory,
            interceptDuringConstruction,
            serialVersionUID);
    this.currentKey = key;	// 赋值到ACG#key属性,后续缓存类会使用这个属性
    // 通过其父类的create()模版方法创建并返回生成类实例。
    Object result = super.create(key);
    return result;
}

二、AbstractClassGenerator

AbstractClassGenerator是cglib包下所有与类字节码生成相关工具类的抽象类。AbstractClassGenerator实际上是一个模版模式,动态生成类字节码的过程封装在create()方法中,并其中提供了许多钩子函数以及供子类实现的基本方法,如自定义类加载器,自定义生成类的类名。除此之外,AbstractClassGenerator还设计了缓存用于提升类字节码生成的效率。

2.1 ACG类间关系

abstract public class AbstractClassGenerator<T>
implements ClassGenerator {
...
}

AbstractClassGenerator类实现了ClassGenerator接口,该接口仅有一个抽象方法generateClass-根据ASM提供的ClassVistor对象生成类。

public interface ClassGenerator {
    void generateClass(ClassVisitor v) throws Exception;
}

实际上,AbstractClassGenerator(下文可能会简称为,ACG)并没有实现generateClass方法,都是由其子类进行实现。ACG类仅负责控制结果类的生成过程模版,具体细节不应该由ACG实现。

2.2 ACG-create类对象模版方法

既然ACG是模版模式实现,那我们这里直攻要害,先来看看AbstractClassGenerator#create()方法的逻辑。

protected Object create(Object key) {
    try {
    	// 1. 获取生成类的类加载器 (内部支持子类自定义默认类加载器)
        ClassLoader loader = getClassLoader();
        // 2. 缓存 Key为类加载器 value为ClassLoaderData对象
        //	(内部维护有generatedClasses缓存)
        Map<ClassLoader, ClassLoaderData> cache = CACHE;
        ClassLoaderData data = cache.get(loader);
        if (data == null) {		
        	// 3. 当前类加载器缓存不存在时,DCL初始化对应的ClassLoaderData对象
            synchronized (AbstractClassGenerator.class) {
                cache = CACHE;
                data = cache.get(loader);
                if (data == null) {
                    Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                    data = new ClassLoaderData(loader);
                    newCache.put(loader, data);
                    CACHE = newCache;
                }
            }
        }
        this.key = key;				// 4. 将key赋值属性key上
        // 5. 通过ClassLoaderData获取生成类对象
        Object obj = data.get(this, getUseCache());	
        if (obj instanceof Class) {
        	// 6. 如果是Class对象,就创建实例。具体创建过程由子类实现
            return firstInstance((Class) obj);
        }
        // 7. 如果是真实实例对象,就创建另外一个实例。具体创建过程由子类实现。
        return nextInstance(obj);
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    }
}

生成类的标准过程中,静态缓存属性ACG#CACHE类型为Map<ClassLoader, ClassLoaderData>,并且在初始化ClssLoaderData时,该map实际类型为WeakHashMap,则ACG中生成类缓存的生命周期与ClassLoader对象一致。
ACG#CACHE仅维护了ClassLoader的映射,但具体生成类的创建过程和缓存逻辑还在ClassLoaderData中。

2.2 ACG-ClassLoaderData

ClassLoaderData是为AbstractClassGenerator的静态内部类,其主要维护了指定类加载器(classLoader)的生成类缓存。

2.2.1 ClassLoaderData属性

ClassLoaderData共有三个对象属性:

  1. WeakReference<ClassLoader> classLoader;
    类加载器。由于外层ACG#CACHE使用WeakHashMap(以classLoader为Key,以ClassLoaderData为Value)进行缓存,而WeakHashMap是将Key使用弱引用包装,但是Vlaue仍是强引用。因此这里的ClassLoaderData#classLoader必须使用弱引用包装,否则就无法GC清楚。
  2. Set<String> reservedClassNames;
    每一个类加载器下生成类的类名不能重复。使用reservedClassNames存储所有生成类类名,并提供getUniqueNamePredicate()方法判定传入类名是否和之前冲突。
  3. LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;
    generatedClasses就是缓存了所有当前类加载器下动态的生成类。LoadingCache和JDK代理中WeakCache功能类似。

2.2.2 ClassLoaderData构造方法

public ClassLoaderData(ClassLoader classLoader) {
    if (classLoader == null) {		 // 必须传入有效类类加载器
        throw new IllegalArgumentException("classLoader == null is not yet supported");
    }
    // 初始化classLoader属性
    this.classLoader = new WeakReference<ClassLoader>(classLoader);
    /**
    * 这里的load就是真正生成类逻辑的函数式变量。
    * load会被传入LoadingCache中,在合适的地方触发load内部逻辑获取生成类并缓存起来!
    **/
    Function<AbstractClassGenerator, Object> load =
            new Function<AbstractClassGenerator, Object>() {
                public Object apply(AbstractClassGenerator gen) {
                	// 重点!
                    Class klass = gen.generate(ClassLoaderData.this);
                    return gen.wrapCachedClass(klass);
                }
            };
    // 初始化generatedClasses属性,即创建LoadingCache缓存实例
    generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}

ClassLoaderData的构造初始化很重要,其中classLoder使用弱引用包装的原因前面已经说过了。后续还有两个重点:

  1. load变量引用的实际逻辑就是生成类的实际逻辑。
  2. load会被用于创建LoadingCache缓存实例。
    关于第1个重点我们先按捺住不继续深追,先知道这里实际上是调用ACG#generate来生成类Class对象的,详细分析在后续2.3节。由于本节是ClassLoaderData,因此我们先看下LoadingCache是如何缓存的。

2.2.3 LoadingCache缓存机制

ClassLoaderData初始化LoadingCache缓存逻辑:

// 标记① (为后文引用)
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);

为进一步了解初始化及缓存过程,先看下LoadingCache的类信息和属性:

public class LoadingCache<K, KK, V> {
	// 内部的缓存映射<Key,Value>
    protected final ConcurrentMap<KK, Object> map;
    protected final Function<K, V> loader;		// 根据第一个类型映射到缓存Value
    protected final Function<K, KK> keyMapper;	// 根据第一个类型映射到缓存Key
    
	public LoadingCache(Function<K, KK> keyMapper, Function<K, V> loader) {
        this.keyMapper = keyMapper;
        this.loader = loader;
        this.map = new ConcurrentHashMap<KK, Object>();
    }
	..
}

从LoadingCache接口上看,标记①出代码中,GET_KEY就是根据ACG对象映射为缓存Key,load变量就是根据ACG对象映射为缓存value。load我们上一个小节说了,就是会调用ACG#generate方法生成动态类Class对象。那GET_KEY是啥?

private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
    public Object apply(AbstractClassGenerator gen) {
        return gen.key;
    }
};

GET_KEY同样也是Function实现的引用,内部逻辑十分简单,返回了ACG#key属性。这个属性实乃为隐藏大佬,简单回顾下,这个key是ACG模版方法的唯一入参(这里可参考2.2节),这就意味着ClassLoaderData缓存生成类Class对象的Key实际上由各个ACG实现类对象决定。

对比JDK动态代理的二级缓存,一级Key也是类加载器,二级Key是由接口列表信息hash生成,value也是动态生成的Class对象。
从整体上看,CGLIB也是二级缓存,二级Key就是LoadingCache#map的Key。那在同样的类加载器下,缓存二级Key如何生成才能区分不同的动态Class对象呢?不同于JDK代理Class仅与接口列表相关,根据1.2节,Enhancer影响动态Class对象的属性很多,必须引入一种机制更巧妙、更快的生成唯一Key。那就是KeyFactory!KeyFactory并不打算在本文介绍,后续有时间再补,其实不理解不影响缓存的逻辑,只要知道ACG具体实现类都对应一个Key,在同一类加载器下对应一个动态Class对象。

LoadingCache的结构清楚了,那如何从该缓存对象中获取动态Class类呢?就在其get方法中。

public V get(K key) {
    final KK cacheKey = keyMapper.apply(key); 		// 获取缓存map的Key
    Object v = map.get(cacheKey);
    if (v != null && !(v instanceof FutureTask)) {	
    	// 如果当前缓存存在且不是FutureTask对象,那就是命中缓存
        return (V) v;
    }
    
	// 缓存中不存在Key(或Value尚未创建完成),会执行根据loader生成value逻辑
    return createEntry(key, cacheKey, v);
}
protected V createEntry(final K key, KK cacheKey, Object v) {
       FutureTask<V> task;
       boolean creator = false;
       if (v != null) {
           // Another thread is already loading an instance
           /**
           * 第三个参数要么为null,要么为FutureTask;
           * 后者就意味着另外有个线程正在执行loader生成动态Class逻辑
           **/
           task = (FutureTask<V>) v;
       } else {
       	/**
       	* 不存在,先创建FutureTask塞入缓存map中,以免并发线程直接执行class生成逻辑。
       	* 注意:这里创建的task的结果不一定会执行,具体还要检查putIfAbsent结果。
       	**/
           task = new FutureTask<V>(new Callable<V>() {
               public V call() throws Exception {
                   return loader.apply(key);
               }
           });
           Object prevTask = map.putIfAbsent(cacheKey, task);	// 并发安全
           if (prevTask == null) {		
               /**
               * map中确实没有task,当前线程的task可以执行,
               * 并且需要把最终结果覆盖FutureTask实例
               **/
               creator = true;
               task.run();
           } else if (prevTask instanceof FutureTask) {
           	// 并发线程抢先一步put到缓存map中
               task = (FutureTask<V>) prevTask;
           } else {
           	// 并发线程抢先一步将结果put到map中去
               return (V) prevTask;
           }
       }

       V result;
       try {
           result = task.get();	// 阻塞等待task任务执行完成,并返回结果
       } catch (InterruptedException e) {
           throw new IllegalStateException("Interrupted while loading cache item", e);
       } catch (ExecutionException e) {
           Throwable cause = e.getCause();
           if (cause instanceof RuntimeException) {
               throw ((RuntimeException) cause);
           }
           throw new IllegalStateException("Unable to load cache item", cause);
       }
       if (creator) {
       	// 如果当前现成的task执行,结果需要放置到map中覆盖futureTask
           map.put(cacheKey, result);
       }
       return result;
   }

LoadingCache缓存的设计十分精彩,相比于JDK代理使用的WeakCache缓存,逻辑简单些。因为WeakCache同时处理二级Key、Value的生成,而LoadingCache只需要处理Value的生成,二级Key交给了具体ACG对象。
代码注释上面写的十分清楚,这里就总结下为什么会引入FutureTask实例作为中间态。因为loader创建Value的逻辑可能十分耗费资源,不使用中间态可能会有多个并发线程通过执行loader创建value的逻辑。而创建FutureTask并设置进缓存map是十分快速的,中间通过putIfAbsent控制并发,就不会出现创建Vlaue逻辑被多次执行的情况。

2.2.4 ClassLoaderData获取动态Class

CGLIB缓存结构基本已经十分清晰了。ACG#cache就是整体的缓存对象,类型为WeakHashMap<ClassLoader, ClassLoaderData>。因此一级Key就是这个map的Key,即类加载器(会使用弱引用包装)。
ClassLoaderData就是负责类加载器下的缓存,内部实现通过LoadingCache实例管理类加载器下不同条件下生成的动态Class对象,二级Key就是ACG#key属性。
因此,ClassLoaderData必须提供get方法,用于根据二级Key来获取对应的动态Class类对象。代码如下:

public Object get(AbstractClassGenerator gen, boolean useCache) {
    if (!useCache) {	
      // 不使用缓存,就直接通过ACG#generate方法生成(与loader变量引用的逻辑一致)。
      return gen.generate(ClassLoaderData.this);
    } else {
      // 通过LoadingCache实例get方法获取Value,其内部可能会通过loader变量引用的方法创建Value
      Object cachedValue = generatedClasses.get(gen);
      return gen.unwrapCachedValue(cachedValue); // 褪去缓存value的弱引用包装
    }
}

2.3 ACG-generate类信息并加载模版方法

从ACG的模版方法中,是通过ClassLoaderData实例来获取动态生成的Class对象。而在2.2节对ClassLoaderData的缓存机制中,我们可以看到实际内部生成Class对象的实际动作由ACG#generate方法完成。该方法也同样是个模版发方法,代码如下:

protected Class generate(ClassLoaderData data) {
    Class gen;
    Object save = CURRENT.get();
    CURRENT.set(this);			// 修改当前线程正在执行生成类的ACG实例
    try {
    	// 1. 获取生成类的类加载器。目前不支持为Null。
        ClassLoader classLoader = data.getClassLoader();
        if (classLoader == null) {
            throw new IllegalStateException("ClassLoader is null Please file an issue at cglib's issue tracker.");
        }
        synchronized (classLoader) {
          // 2. 生成类名,默认保证了类加载器下不能生成重复类名
          String name = generateClassName(data.getUniqueNamePredicate());              
          data.reserveName(name);
          this.setClassName(name);
        }
        /**
        * 3. 根据attemptLoad属性值,先尝试使用类加载器加载
        * 因为前面生成的类名默认保证在同一类加载器下唯一,这里使用类加载器加载一个新类名,肯定加载不到,因此默认attemptLoad为false。(ps:确实没有必要设置为true)
        **/
        if (attemptLoad) {
            try {
                gen = classLoader.loadClass(getClassName());
                return gen;
            } catch (ClassNotFoundException e) {
                // ignore
            }
        }
        // 4. 根据ACG#strategy的策略来生成字节码【重点】
        byte[] b = strategy.generate(this);
        // 5. 使用ASM底层工具获取类字节码的类名。(generate内部可能修改类名)
        String className = ClassNameReader.getClassName(new ClassReader(b));
        /** 6. 获取动态生成Class的保护域对象,后续会加载class类时会考虑。
        * 内部加载优先使用java.lang.ClassLoader#defineClass加载该类,
        * 其次使用sun.misc.Unsafe#defineClass加载该类
        **/
        ProtectionDomain protectionDomain = getProtectionDomain();
        synchronized (classLoader) { // just in case
            if (protectionDomain == null) {
            	// 加载不考虑protectionDomain
                gen = ReflectUtils.defineClass(className, b, classLoader);
            } else {
            	// 加载考虑protectionDomain
                gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
            }
        }
        return gen;
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    } finally {
        CURRENT.set(save);
    }
}

这里大概总结下ACG生成类信息并加载到JVM的标准化流程:

  1. 获取对应的类加载器
    获取类时就指定了类加载器,ACG实现类可重写getDefaultClassLoader()设置模版默认类加载器,对于Enhancer来说,默认首选返回被代理父类加载器,次选返回被代理接口的类加载器,获者返回null(这部分可见ACG#getClassLoader())。

    增强子类的类加载器选择顺序:父类加载器>接口类加载器>Ehancer类加载器>线程上下文加载器>异常

  2. 获取生成类的类名
    ACG生成类名是通过命名策略(NamingPolicy)产生。ACG实现类可通过setNamingPolicy设置命名策略,默认策略为DefaultNamingPolicy。有关于命名策略将在2.3.1节叙述。
  3. 生成动态Class字节码
    ACG生成类字节码是通过类生成策略(GeneratorStrategy)产生。ACG实现类可通过setStrategy设置生成策略,默认策略为DefaultGeneratorStrategy。有关于生成策略将在2.3.2节叙述。
  4. 类加载到JVM中
    将生成类的字节码信息加载到JVM中称为Class对象的方式分为两种,优先使用java.lang.ClassLoader#defineClass加载,其次使用sun.misc.Unsafe#defineClass加载该类。此外,加载类时还需要考虑父类或者接口的保护域信息。

2.3.1 类名生成策略

ACG动态生成的类名是通过设置的命名策略产生的。使用者可以自定义命名策略,需实现NamingPolicy接口。该接口声明了两个抽象方法,getClassName(…)及equals(…),其中equals方法暂时内部没有使用到,因此我们先看下getClassName(…)方法:

String getClassName(String prefix, String source, Object key, Predicate names);

方法参数含义列举如下:

  • String prefix:由ACG实现类指定的点分割路径;在Enhancer中是父类或接口的全限定名。多个接口的情况下,根据接口的权限选择,优先顺序选择非公共权限的接口路径。
  • String source:ACG实现类的全限定名。如net.sf.cglib.Enhancer。
  • Object key:该key表示动态生成类Class的一系列参数状态。一般来说一个Key对应一个Class,因此在Enhancer中,该Key就是使用KeyFactory生成的二级Key。
  • Predicate names:断言函数,用于保证在同一个类加载器下的类名唯一性。

在CGLIB仅提供了一个NamingPolicy的实现类-DefaultNamingPolicy,也是ACG默认的命名策略。我们看下DefaultNamingPolicy是如何生成类名的:

public String getClassName(String prefix, String source, Object key, Predicate names) {
    if (prefix == null) {	// prefix为空时默认值
        prefix = "net.sf.cglib.empty.Object";
    } else if (prefix.startsWith("java")) {	
    	// 这个没太懂有啥特殊的地方,后续再看哈
        prefix = "$" + prefix;
    }
    // 拼接基本类名
    String base =
        prefix + "$$" + 
        source.substring(source.lastIndexOf('.') + 1) +	
        getTag() + "$$" +
        Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode());
    String attempt = base;
    int index = 2;
    while (names.evaluate(attempt))  // 重名通过增加数字保证唯一性
        attempt = base + "_" + index++;
    return attempt;
}

从上述逻辑中看,prefix其实定义了生成类的包名和类名前缀(父类名),然后拼接生成源类的类名,然后拼接命名策略标签,然后拼接类唯一Key的hashCode(STRESS_HASH_CODE,测试模式,不需要关注),然后根据类是否唯一来选择拼接递增数字。
CGLIB原理简析-前篇第一章示例中,prefix=“com.design.代理模式.cglib.Student”,source=“net.sf.cglib.Enhancer”,DefaultNamingPolicy#getTag=“ByCGLIB”。因此最终生成动态类名为Student$$EnhancerByCGLIB$86327ae0,其中86327ae0为二级Key的hashCode值。
通过类名生成策略的讲解,以后我们在看到CGLIB动态生成类时,从其全限定名就知道该动态类的父类或接口、生成源(由哪个类生成)、是否为默认策略等信息。

  1. 使用者完全可以实现NamingPolicy接口,并通过setNamingPolicy设置命名策略,因此ACG其实无法保证生成类名的唯一性。如果存在重名的情况下,可以设置attemptLoad为true来尝试加载Class。
  2. 一定要区分生成类名和最终类名。通过命名策略生成的类名可能有重复,但是在类加载器中的类名一定不会重复。

2.3.2 类字节码生成策略

同样的,ACG动态生成类字节码也是通过设置策略产生的。使用者也可以自定字节码生成策略,需实现GeneratorStrategy接口。该接口也声明了两个抽象方法,generate(…)及equals(…),其中equals方法暂时内部没有使用到,因此我们先看下generate(…)方法:

byte[] generate(ClassGenerator cg) throws Exception;

返回值就是字节码数组,只有唯一的入参是ClassGenerator对象。前面说过ClassGenerator是个接口,ACG就是实现了这个接口,因此一般这里传入的就是ACG的实现类对象。
在CGLIB中也仅提供了一个直接实现GeneratorStrategy接口的实现类-DefaultGeneratorStrategy,也是ACG默认的字节码生成策略。我们看下其generate方法:

public byte[] generate(ClassGenerator cg) throws Exception {
	// 1. 获取ClassWriter实例;
	// 	这里使用的CGLIB继承自ClassWriter的子类DebuggingClassWriter 
    DebuggingClassWriter cw = getClassVisitor();
    // 将ACG实例转换一层,一般是一个代理生成器,如TransformingClassGenerator
    transform(cg).generateClass(cw);
    // 将生成的字节码数组转换一层。目的就是为了提供拦截的方法。
    return transform(cw.toByteArray());
}

实际上,generate也可以认为是模版方法,使用者可以继承DefaultGeneratorStrategy类,并重写两个transform方法在生成字节码动作做一些事情,参考UndeclaredThrowableStrategy。
默认情况下ACG就是DefaultGeneratorStrategy类,两处transform都是直接返回的,因此默认generate方法就是获取ClassWriter示例,并调用ACG实现类的generateClass方法来生成动态字节码(还记得之前说过,ACG实现了ClassGenerator类,但并未实现generateClass方法)。因此如何生成字节码的呢?这个我们要通过ACG的实现子类去看。下一个章节我们就简单聊下Ehancer这个ACG实现类的generateClass方法逻辑。

三、Ehancer生成类过程

Ehancer作为重要的ACG实现类,本章节简单聊下其生成动态类信息的过程。

public void generateClass(ClassVisitor v) throws Exception {
		// 父类默认设计Object类,要么是用户指定类
        Class sc = (superclass == null) ? Object.class : superclass;

        if (TypeUtils.isFinal(sc.getModifiers()))	
			// 检查类不能是final类型,不允许继承
            throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
        // 获取父类所有的声明构造器,且默认过滤掉私有构造器
        List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
        filterConstructors(sc, constructors);

        /**
        * 获取需要实现或重写的所有的方法actualMethods
        * interfaceMethods所有接口方法,forcePublic存储Public方法的签名Key
        * getMethods内部会过滤掉静态、私有、final修饰的方法,也会根据方法签名Key去重(KEY_FACTORY)
        **/
        List actualMethods = new ArrayList();
        List interfaceMethods = new ArrayList();
        final Set forcePublic = new HashSet();
        getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);

		// 处理各个方法的权限符
        List methods = CollectionUtils.transform(actualMethods, new Transformer() {
            public Object transform(Object value) {
                Method method = (Method)value;
                int modifiers = Constants.ACC_FINAL
                    | (method.getModifiers()
                       & ~Constants.ACC_ABSTRACT
                       & ~Constants.ACC_NATIVE
                       & ~Constants.ACC_SYNCHRONIZED);
                if (forcePublic.contains(MethodWrapper.create(method))) {
                    modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
                }
                return ReflectUtils.getMethodInfo(method, modifiers);
            }
        });

        ClassEmitter e = new ClassEmitter(v);
        if (currentData == null) {
        	/**
        	* 生成类的版本、访问权限、类名、父类类型、接口列表,来源
        	* useFactory属性决定了生成类是否继承Factory接口
        	**/
        	e.begin_class(Constants.V1_8,
                      Constants.ACC_PUBLIC,
                      getClassName(),
                      Type.getType(sc),
                      (useFactory ?
                       TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
                       TypeUtils.getTypes(interfaces)),
                      Constants.SOURCE_FILE);
        } else {
            e.begin_class(Constants.V1_8,
                    Constants.ACC_PUBLIC,
                    getClassName(),
                    null,
                    new Type[]{FACTORY},
                    Constants.SOURCE_FILE);
        }
        // 将构造方法转换为了MethodInfo对象
        List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());

		// 声明动态类中私有CGLIB$BOUND布尔类型属性
        e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);		
        // 声明动态类中公共静态CGLIB$FACTORY_DATA类型为Object属性
        e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);
        if (!interceptDuringConstruction) {
        	// 如果设置interceptDuringConstruction属性为false,会声明动态类中私有CGLIB$CONSTRUCTED属性
            e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
        }
        // 声明动态类中私有静态final的CGLIB$THREAD_CALLBACKS类型为ThreadLocal属性
        e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
        // 声明动态类中私有静态final的CGLIB$STATIC_CALLBACKS类型为Callback属性
        e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
        if (serialVersionUID != null) {
        	// 声明动态类中私有静态final的serialVersionUID类型为Long属性,并赋值serialVersionUID
            e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
        }

        for (int i = 0; i < callbackTypes.length; i++) {
       	 	// 声明动态类中私有的CGLIB$CALLBACK_{index}回调类型属性
            e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
        }
        // 声明动态类中静态私有的CGLIB$CALLBACK_FILTER属性,类型为Object
        e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);

        if (currentData == null) {
			// 产生生成类中所有方法
            emitMethods(e, methods, actualMethods);
            // 产生生成类中所有构造方法
            emitConstructors(e, constructorInfo);
        } else {
            emitDefaultConstructor(e);
        }
        // 生成公开静态方法CGLIB$SET_THREAD_CALLBACKS()方法
        emitSetThreadCallbacks(e);
        // 生成公开静态的CGLIB$SET_STATIC_CALLBACKS()方法
        emitSetStaticCallbacks(e);
        // 生成私有静态final的CGLIB$BIND_CALLBACKS()方法
        emitBindCallbacks(e);

		/**
		* 下面是生成Factory的实现方法
		**/
        if (useFactory || currentData != null) {
            int[] keys = getCallbackKeys();
            emitNewInstanceCallbacks(e);
            emitNewInstanceCallback(e);
            emitNewInstanceMultiarg(e, constructorInfo);
            emitGetCallback(e, keys);
            emitSetCallback(e, keys);
            emitGetCallbacks(e);
            emitSetCallbacks(e);
        }

        e.end_class();
    }

这一部分就是Enhancer实际通过ASM框架生成类的逻辑,结合CGLIB原理简析-前篇中对增强代理类公开方法的讲解来看,逻辑还是十分简单的。但是,在实际使用ASM的一些细节上,本文不再继续深追,后续看时间详细聊下ASM相关知识。
至此,Enhancer动态生成代理类信息的过程基本已经十分清楚了。Enhancer实际继承了AbstractClassGenerator抽象类,该抽象类有重要的两个模版方法,分别是:

  • create:创建类信息并返回实例化对象
    这一部分主要使用ClassLoaderData类缓存或生成某一加载器下的所有动态生成Class对象,其中缓存二级Key是由Ehancer类依据父类或接口等特征通过KeyFactory生成。获取到Class对象之后再进行实例化。
  • generate:生成类信息
    这一部分主要是在ClassLoaderData缓存中不存在时,会调用ACG#generate模版进行生成动态类信息。生成类信息包括类名、类字节码分别是通过不同策略进行生成。类字节码策略中会调用ACG实现类的generteClass方法生成,即第三章讲解的通过ASM生成代理类信息的过程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值