上一节我们分析了cglib方式实现aop的基本过程,本文将继续上一篇的内容,具体讲讲代理对象的实现细节。提到代理对象的产生,就不得不提Enhancer,这是cglib中的一个字节码增强器,通过它我们可以对目标类进行扩展。
本文主要分析以下两个问题:
1.cglib如何生成代理类
2.cglib生成代理的方式中,哪些方法不能被代理
3.cglib的二级缓存机制
1.源码分析
Enhancer中产生代理类的入口是几个签名不同的create()方法,但是这几个create()方法最终都会调用createHelper()方法,因此我们就从createHelper()方法着手:
private Object createHelper() {
// 这里主要是一些参数校验,比较简单
this.preValidate();
// 根据代理配置生成缓存的key,作为二级缓存的key值,而一级缓存的key则是ClassLoader
Object key = KEY_FACTORY.newInstance(this.superclass != null?this.superclass.getName():null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO?null:new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
this.currentKey = key;
// 调用父类AbstractClassGenerator的create()方法
Object result = super.create(key);
return result;
}
AbstractClassGenerator是cglib中一个很重要的类,是字节码生成过程中的一个核心调度者,包括缓存、命名策略、字节码生成策略都由它定义,Enhancer就是它的一个子类。
protected Object create(Object key) {
try {
// 获取类加载器
ClassLoader loader = this.getClassLoader();
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
// 优先从缓存加载,根据ClassLoader区分
AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
// 缓存为空,则需要进行初始化
if(data == null) {
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if(data == null) {
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
data = new AbstractClassGenerator.ClassLoaderData(loader);
// 放入缓存
newCache.put(loader, data);
CACHE = newCache;
}
}
}
// 从缓存加载
this.key = key;
Object obj = data.get(this, this.getUseCache());
return obj instanceof Class?this.firstInstance((Class)obj):this.nextInstance(obj);
}
... 异常处理省略
}
类加载器是按照如下顺序来获取的:加载父类或者接口的类加载器 -> 自己的类加载器 -> 线程上下文类加载器,这个过程在上一篇也有提到,这里不再展开。
缓存在这个构造函数中进行初始化:
protected static class ClassLoaderData {
public ClassLoaderData(ClassLoader classLoader) {
if(classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
} else {
this.classLoader = new WeakReference(classLoader);
Function<AbstractClassGenerator, Object> load = new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
// 产生字节码文件
Class klass = gen.generate(ClassLoaderData.this);
return gen.wrapCachedClass(klass);
}
};
// 生成二级缓存
this.generatedClasses = new LoadingCache(GET_KEY, load);
}
}
// 判断是否使用缓存
public Object get(AbstractClassGenerator gen, boolean useCache) {
if(!useCache) {
return gen.generate(this);
} else {
// 从二级缓存中取出代理对象
Object cachedValue = this.generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
}
protected Class generate(AbstractClassGenerator.ClassLoaderData data) {
Object save = CURRENT.get();
CURRENT.set(this);
try {
ClassLoader classLoader = data.getClassLoader();
if(classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " + this.getClassName() + ". It seems that the loader has been expired from a weak reference somehow. Please file an issue at cglib's issue tracker.");
} else {
String className;
synchronized(classLoader) {
// 根据命名策略生成代理类类名
className = this.generateClassName(data.getUniqueNamePredicate());
data.reserveName(className);
this.setClassName(className);
}
Class gen;
if(this.attemptLoad) {
try {
gen = classLoader.loadClass(this.getClassName());
Class var25 = gen;
return var25;
} catch (ClassNotFoundException var20) {
;
}
}
// 生成二进制流,默认实现DefaultGeneratorStrategy
byte[] b = this.strategy.generate(this);
className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = this.getProtectionDomain();
synchronized(classLoader) {
if(protectionDomain == null) {
// 根据二进制流生成字节码
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
Class var8 = gen;
return var8;
}
}
... 省略异常处理
生成代理类类名的具体逻辑如下:
public String getClassName(String prefix, String source, Object key, Predicate names) {
// prefix一般就是目标类的全限定名
if(prefix == null) {
prefix = "org.springframework.cglib.empty.Object";
} else if(prefix.startsWith("java")) {
prefix = "$" + prefix;
}
// source就是Enhancer的全限定名
// source.substring(source.lastIndexOf(46) + 1)就是去Enhancer的简称
// this.getTag()返回的是"ByCGLIB"
String base = prefix + "$$" + source.substring(source.lastIndexOf(46) + 1) + this.getTag() + "$$" + Integer.toHexString(STRESS_HASH_CODE?0:key.hashCode());
String attempt = base;
for(int var7 = 2; names.evaluate(attempt); attempt = base + "_" + var7++) {
;
}
return attempt;
}
public class DefaultGeneratorStrategy implements GeneratorStrategy {
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = this.getClassVisitor();
this.transform(cg).generateClass(cw);
return this.transform(cw.toByteArray());
}
}
利用Enhancer来生成代理类,底层也是采用了asm框架,具体实现如下:
public void generateClass(ClassVisitor v) throws Exception {
Class sc = this.superclass == null?Object.class:this.superclass;
if(TypeUtils.isFinal(sc.getModifiers())) {
throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
} else {
List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
this.filterConstructors(sc, constructors);
List actualMethods = new ArrayList();
List interfaceMethods = new ArrayList();
final Set forcePublic = new HashSet();
// 采用递归的方式,找到目标类的父类、接口的所有方法,并过滤掉满足条件的方法,具体条件后文有详细说明
getMethods(sc, this.interfaces, actualMethods, interfaceMethods, forcePublic);
// 对方法的修饰符作了变化,保存到methods中,转换之前的方法保存在actualMethods中
List methods = CollectionUtils.transform(actualMethods, new Transformer() {
public Object transform(Object value) {
Method method = (Method)value;
// 在Modifier类中,1024、256、32、16分别表示abstract、native、synchronized、final修饰符,因此这句话的意思是将abstract、native、synchronized修饰符全部去掉,然后加上final修饰符
int modifiers = 16 | method.getModifiers() & -1025 & -257 & -33;
// 同理,这里是把protected修饰符换成public
if(forcePublic.contains(MethodWrapper.create(method))) {
modifiers = modifiers & -5 | 1;
}
return ReflectUtils.getMethodInfo(method, modifiers);
}
});
// 这里有一段是根据asm框架产生字节码了,还没看懂,先跳过o(╯□╰)o
......
if(this.currentData == null) {
// 上一篇讲过,CallbackFilter作为回调过滤器,其核心方法为accept(),返回值为int类型,代表了回调入口在callbacks数组中的位置,这里就是完成了CallbackFilter的处理,确定每个方法分别有哪个过滤器来处理
this.emitMethods(e, methods, actualMethods);
this.emitConstructors(e, constructorInfo);
} else {
this.emitDefaultConstructor(e);
}
......
e.end_class();
}
}
getMethods方法具体实现逻辑:
private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic) {
// 递归添加父类的所有方法
ReflectUtils.addAllMethods(superclass, methods);
List target = interfaceMethods != null?interfaceMethods:methods;
// 递归添加接口的所有方法
if(interfaces != null) {
for(int i = 0; i < interfaces.length; ++i) {
if(interfaces[i] != Factory.class) {
ReflectUtils.addAllMethods(interfaces[i], target);
}
}
}
if(interfaceMethods != null) {
if(forcePublic != null) {
forcePublic.addAll(MethodWrapper.createSet(interfaceMethods));
}
methods.addAll(interfaceMethods);
}
// 过滤掉静态方法,在Modifier类中,静态方法的标识就是0x00000008
CollectionUtils.filter(methods, new RejectModifierPredicate(8));
// 过滤掉不可见的方法(包括两类:私有方法、默认修饰符且与目标类不在同一个包中的方法)
CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
// 过滤掉重复的方法(方法名、入参和返回类型都相同的方法)
CollectionUtils.filter(methods, new DuplicatesPredicate());
// 过滤掉final方法,在Modifier类中,静态方法的标识就是0x00000010
CollectionUtils.filter(methods, new RejectModifierPredicate(16));
}
emitMethods方法具体实现逻辑:
private void emitMethods(ClassEmitter ce, List methods, List actualMethods) {
CallbackGenerator[] generators = CallbackInfo.getGenerators(this.callbackTypes);
Map groups = new HashMap();
final Map indexes = new HashMap();
final Map originalModifiers = new HashMap();
final Map positions = CollectionUtils.getIndexMap(methods);
Map declToBridge = new HashMap();
Iterator it1 = methods.iterator();
Iterator it2 = actualMethods != null?actualMethods.iterator():null;
while(it1.hasNext()) {
MethodInfo method = (MethodInfo)it1.next();
Method actualMethod = it2 != null?(Method)it2.next():null;
// 选择具体的回调过滤器
int index = this.filter.accept(actualMethod);
if(index >= this.callbackTypes.length) {
throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
}
// 把方法和其对应的修饰符的映射关系保存起来
originalModifiers.put(method, new Integer(actualMethod != null?actualMethod.getModifiers():method.getModifiers()));
// 把方法和其对应的回调过滤器下表的映射关系保存起来
indexes.put(method, new Integer(index));
List group = (List)groups.get(generators[index]);
if(group == null) {
groups.put(generators[index], group = new ArrayList(methods.size()));
}
((List)group).add(method);
// 建立类和桥接方法之间的映射关系
// 桥接方法:jdk1.5引入了泛型,并且在编译期会进行类型擦除,因此字节码文件中集合元素类型都是Object,同时由于对类型的校验也提前到了编译期,因此编译期会生成一个桥接方法,将Object类型转换为实际类型。
if(TypeUtils.isBridge(actualMethod.getModifiers())) {
Set bridges = (Set)declToBridge.get(actualMethod.getDeclaringClass());
if(bridges == null) {
bridges = new HashSet();
declToBridge.put(actualMethod.getDeclaringClass(), bridges);
}
((Set)bridges).add(method.getSignature());
}
}
// 又是一堆根据asm生成字节码的逻辑,暂时略过o(╯□╰)o
......
}
2.测试
好了,源码总是虚无缥缈的,我们接下来举一个实际的栗子来看一看。
目标类:
public class Target {
public void exeTarget() {
System.out.println("execute target.");
}
}
增强类:
public class BeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("before advice.");
}
}
配置文件:
<bean id="adviceSeq" class="org.springframework.aop.framework.ProxyFactoryBean"
p:target-ref="target"
p:proxyTargetClass="true"
p:frozen="true"
p:interceptorNames="beforeAdvice"/>
测试类:
public class AdviceSeqTest {
public static void main(String[] args) {
// 将产生的代理类文件写入磁盘
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, ".//");
String configPath = "advice/seq/beans.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configPath);
Target target = (Target) context.getBean("adviceSeq");
target.exeTarget();
}
}
运行测试类后,得到的代理类class文件名为Target$$EnhancerBySpringCGLIB$$8b53f595.class,跟我们前面的分析一致,目标方法的代理方法为如下,静态方法exeStaticTarget()、私有privateMethod()和final方法finalMethod()在生成的代理类中都不存在:
// 跟之前分析的一样,方法加上了final修饰符
public final void exeTarget() {
try {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
// 如果回调函数不为空,执行拦截,否则直接调用目标方法
if(var10000 != null) {
var10000.intercept(this, CGLIB$exeTarget$6$Method, CGLIB$emptyArgs, CGLIB$exeTarget$6$Proxy);
} else {
super.exeTarget();
}
} catch (Error | RuntimeException var1) {
throw var1;
} catch (Throwable var2) {
throw new UndeclaredThrowableException(var2);
}
}
网友评论