通过上一篇文章对Enhancer类的使用,我们大致对cglib的proxy功能有了一个基本了解,本篇从Enhancer类的父类AbstractClassGenerator源码入手,试着剖析一下作者在写cglib框架时候可能的思想。仔细阅读源码就发现该类作为父类,被很多的类继承,比如Enhancer、BeanCopier内部类、KeyFactory内部类等。可以说所有cglib内部使用proxy的地方都需要继承这个类作为父类。
AbstractClassGenerator内部维护了两级缓存,抽象了很多操作,并且定义了一些抽象方法用于具体的Generator子类去实现,从而实现了高可用的、灵活多变的proxy子类。
package net.sf.cglib.core;
import org.objectweb.asm.ClassVisitor;
public interface ClassGenerator {
void generateClass(ClassVisitor v) throws Exception;
}
从源码分析,我们看到AbstractClassGenerator实现了ClassGenerator接口。而接口只提出了一个方法,从字面意义上理解为生成Class,入参为asm ClassVisitor,虽然只有一行代码。但是这基本上就是作者的根本思想了。用asm生成一个Class类。
/*****
* 创建一个被代理对象,
* 该类被所有AbstractClassGenerator的子类Generator所调用,
* @param key
* @return
*/
protected Object create(Object key) {
try {
//一级缓存loader作为缓存key
ClassLoader loader = getClassLoader();
//获取对应的一级缓存Value
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
//static volatile 只有一个实例,存在线程竞争
if (data == null) {
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;
//通过ClassLoaderData获取实例,存在判定是否用到缓存的逻辑
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
create方法为所有子类生成proxy的统一调用入口。如上,create方法,接收一个key,返回一个Object对象,该Object对象的返回取决于firstInstance或nextInstance的实现。如下,比如Enhancer的实现:
//提出概念,获取第一个proxy实例,如果map中获取的对象为Class对象
protected Object firstInstance(Class type) throws Exception {
if (classOnly) {
return type;
} else {
return createUsingReflection(type);
}
}
private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>();
//获取对应的一级缓存Value
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
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;
}
}
}
如上,通过WeakHashMap定义了一级缓存,因为同一个class类被不同的ClassLoader加载以后,它们依然不同,换句话说,只有ClassLoader和Class才可以确定该Class在jvm中的唯一性.这样也就解释了为什么用
这里简单说一下WeakHashMap,该类除了将Entry继承WeakReference,在其他层面基本上与普通的HashMap没有什么区别,只不过在每次操作map的时候都会调用expungeStaleEntries()方法,将ReferenceQueue中已经被gc的对象,在链表的存储中删除而已。
这和WeakReference本身的构造有关系,因WeakReference本身就提供了这种机制,在声明WeakReference对象的同时提供了ReferenceQueue传入的构造,当WeakReference对象被gc的同时,被gc掉的对象也会在ReferenceQueue中保存一份。而WeakHashMap的Entry正是利用了这个机制。
建议参考blog:
http://www.cnblogs.com/xdouby/p/6793184.html
这里由于CACHE对象是static的。所以只有一个实例,我们看到锁内部的操作是对于CACHE变量不断的new一个WeakHashMap的实例,并且在锁最后一步赋值给CACHE,博主的理解是这恰巧用到了LoadStore屏障,保证了指令执行顺序,并且及时刷新到主存区域,以供下一个线程读到正确的值。
虽然ClassLoader作为key传入了WeakHashMap中,但我们不确定传入的该loader key是否还有强引用指向呢?如果loader还有强引用指向的话,那该缓存是不是永远不会清理掉该key呢?换句话说,作为key的loader对象生命周期是什么样子的呢?
this.key = key;
//通过ClassLoaderData获取实例,存在判定是否用到缓存的逻辑
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
我们继续上面的话题,此时我们由
public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
}
this.classLoader = new WeakReference<ClassLoader>(classLoader);
//LoadingCache中的loader
Function<AbstractClassGenerator, Object> load =
new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this);
return gen.wrapCachedClass(klass);
}
};
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}
public Object get(AbstractClassGenerator gen, boolean useCache) {
//判定是否使用缓存
if (!useCache) {
//不使用缓存
return gen.generate(ClassLoaderData.this);
} else {
//使用缓存
//enhancerkey net.sf.cglib.proxy.Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
一路深入,我们最终发现原来调用的还是LoadingCache中的get方法,并且传入的是AbstractClassGenerator当前实例对象,而此前所做的一些操作也不过是在为LoadingCache中的操作打基础罢了。此时LoadingCache才是才神秘的,我们继续往下。
public interface Function<K, V> {
V apply(K key);
}
package net.sf.cglib.core.internal;
import java.util.concurrent.*;
/*****
* 缓存对象,被包装在ClassLoaderData中GeneratedClass
* get 返回相关对象
* @param AbstractClassGenerator
* @param Object
* @param Object
*
* new LoadingCache(GET_KEY, load);
*
*
* 真正的缓存对象的提取
* Function 抽象一个行为,用于封装一些逻辑,将特定的K传入,返回特定的value
*/
public class LoadingCache<K, KK, V> {
//真正的二级缓存,value为WeakReference类型
protected final ConcurrentMap<KK, Object> map;
//该Function的apply方法将决定task的get的返回。也就间接的决定了map内存入的值
protected final Function<K, V> loader;
//封装了返回相应cachekey的逻辑
protected final Function<K, KK> keyMapper;
public static final Function IDENTITY = new Function() {
public Object apply(Object key) {
return key;
}
};
/****
*
* @param keyMapper 用于转换key apply GET_KEY的实现,返回一个key
* private static final Function GET_KEY = new Function() {
* public Object apply(AbstractClassGenerator gen) {
* return gen.key;
* }
* };
*
* @param loader 用于转换存储的value Function load =
* new Function() {
* public Object apply(AbstractClassGenerator gen) {
* Class klass = gen.generate(ClassLoaderData.this);
* return gen.wrapCachedClass(klass);
* }
* };
*/
public LoadingCache(Function<K, KK> keyMapper, Function<K, V> loader) {
this.keyMapper = keyMapper;
this.loader = loader;
this.map = new ConcurrentHashMap<KK, Object>();
}
@SuppressWarnings("unchecked")
public static <K> Function<K, K> identity() {
return IDENTITY;
}
public V get(K key) {
final KK cacheKey = keyMapper.apply(key);
Object v = map.get(cacheKey);
if (v != null && !(v instanceof FutureTask)) {
return (V) v;
}
return createEntry(key, cacheKey, v);
}
/******
* 线程竞争,则只有一个线程会竞争成功,没有竞争成功的线程则使用get请求重新加载
* 当多个线程竞争同一个futuretask对象时,只有一个get方法在运行。
*/
/**
* Loads entry to the cache.
* If entry is missing, put {@link FutureTask} first so other competing thread might wait for the result.
* @param key original key that would be used to load the instance
* @param cacheKey key that would be used to store the entry in internal map
* @param v null or {@link FutureTask}
* @return newly created instance
*/
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
task = (FutureTask<V>) v;
} else {
task = new FutureTask<V>(new Callable<V>() {
public V call() throws Exception {
return loader.apply(key);
}
});
//如果已经存在,则不会覆盖已有的值,直接返回已存在的值
//如果不存在,则向map中添加该键值对,并返回null
Object prevTask = map.putIfAbsent(cacheKey, task);
if (prevTask == null) {
// creator does the load
creator = true;
task.run();
} else if (prevTask instanceof FutureTask) {
task = (FutureTask<V>) prevTask;
} else {
return (V) prevTask;
}
}
V result;
try {
result = task.get();
} 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) {
map.put(cacheKey, result);
}
return result;
}
}
成员变量提供了两个Function的概念,它是一个单函数接口,其实它是对trueKey = Function.apply(key),以及trueValue = Function.apply(value)的一个封装。相当于对map的kv进行了一层拦截。这里博主将Enhancer类的调用放入了进去。我们看到存入value的时候我们还用到了gen.wrapCachedClass包装方法,转换过来也就是
protected T wrapCachedClass(Class klass) {
return (T) new WeakReference(klass);
}
又是WeakReference,所以,二级缓存的本质是Map中的存储value转换成了一个弱引用,以此来实现了二级缓存
这里值得一提的是,如果FutureTask的get方法没有执行完成,那么在并发情况下,只会有一个线程在执行,其他线程要让出cpu执行权,阻塞等待,直到get方法有结果返回,以下提供两篇文章url
FutureTask:https://www.cnblogs.com/maypattis/p/5827671.html
LoadingCache的转换解析:https://zhuanlan.zhihu.com/p/41947763
以上就是cglib的proxy创建都需要AbstractClassGenerator的缓存解析,有任何问题欢迎拍砖交流,这里总结一下我们用到的类清单,以便以后写出来更好的demo,更深层次的理解