CGLIB動態代理示例與原始碼解析
1. 原理,代理模式
代理模式的本質:呼叫方--->代理方--->實現方。
1.1 動態代理模式步驟
生成代理類二進位制位元組碼,可配置引數生成檔案。
classloader load二進位制位元組碼,生成Class物件( 可使用public static Class<?> forName(String className))
Class物件反射構造方法,構造方法newInstance建立物件
2. CGLib代理示例
pom.xml加入
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
public class HelloService { public void sayHello(String something) { System.out.println("hello, " + something); } } public class HelloCGLibProxy implements MethodInterceptor { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("-----------"+method.getName()+"-------"); return methodProxy.invokeSuper(o, objects); } } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloService.class); enhancer.setCallback(new HelloCGLibProxy()); Object obj = enhancer.create(); HelloService helloService = (HelloService) obj; helloService.sayHello("ok"); } -----------sayHello------- hello, ok
3. 原始碼分析
核心方法
enhancer.create()
看註釋一目瞭然,Generate a new class if necessary
/** * Generate a new class if necessary and uses the specified * callbacks (if any) to create a new object instance. * Uses the no-arg constructor of the superclass. * @return a new instance */ public Object create() { classOnly = false; argumentTypes = null; return createHelper(); }
createHelper()
private static final EnhancerKey KEY_FACTORY =
(EnhancerKey)KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null);
public interface EnhancerKey {
public Object newInstance(String type,
String[] interfaces,
WeakCacheKey<CallbackFilter> filter,
Type[] callbackTypes,
boolean useFactory,
boolean interceptDuringConstruction,
Long serialVersionUID);
}
private Object createHelper() {
//驗證
preValidate();
//生成key,EnhancerKey KEY_FACTORY初始化的時候,通過CGLIB動態生成實現類
//先自己CGLIB給自己動態建立實現類了
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;
//父類使用EnhancerKey建立物件
Object result = super.create(key);
return result;
}
除錯看圖,傳入了代理的類物件和方法攔截器(CGLIB的核心思想)
3.1 建立KeyFactory物件,此處居然就使用了CGLIB動態代理技術,下面逐一分析。
KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null) //動態建立EnhancerKey實現類
public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
List<KeyFactoryCustomizer> next) {
Generator gen = new Generator();
gen.setInterface(keyInterface);
if (customizer != null) {
gen.addCustomizer(customizer);
}
if (next != null && !next.isEmpty()) {
for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
gen.addCustomizer(keyFactoryCustomizer);
}
}
gen.setClassLoader(loader);
return gen.create();
}
public KeyFactory create() {
setNamePrefix(keyInterface.getName());
return (KeyFactory)super.create(keyInterface.getName());
}
super.create(keyInterface.getName()
使用WeakHashMap快取,以classLoader為key,value是ClassLoaderData
private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>();
protected Object create(Object key) {
try {
ClassLoader loader = getClassLoader();
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;
}
}
}
this.key = key;
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);
}
}
我們看new ClassLoaderData()發生了什麼
public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
}
this.classLoader = new WeakReference<ClassLoader>(classLoader);
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);
}
Class klass = gen.generate(ClassLoaderData.this);
protected Class generate(ClassLoaderData data) {
Class gen;
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 " +
getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
"Please file an issue at cglib's issue tracker.");
}
synchronized (classLoader) {
//動態代理生成類名稱
String name = generateClassName(data.getUniqueNamePredicate());
data.reserveName(name);
this.setClassName(name);
}
//有代理類直接載入
if (attemptLoad) {
try {
gen = classLoader.loadClass(getClassName());
return gen;
} catch (ClassNotFoundException e) {
// ignore
}
}
//生成位元組碼
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
//載入類,生成class物件
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
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);
}
}
類名生成規則,使用$和$$加雜湊值,跟上面除錯的程式碼一致。
public String getClassName(String prefix, String source, Object key, Predicate names) {
if (prefix == null) {
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;
}
下面看位元組碼生成類
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = getClassVisitor();
transform(cg).generateClass(cw);
return transform(cw.toByteArray());
}
public class DebuggingClassWriter extends ClassVisitor {
public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation";
//這裡可以設定寫檔案的位置
private static String debugLocation = System.getProperty("cglib.debugLocation");
private static Constructor traceCtor;
private String className;
private String superName;
public DebuggingClassWriter(int flags) {
super(327680, new ClassWriter(flags));
}
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.className = name.replace('/', '.');
this.superName = superName.replace('/', '.');
super.visit(version, access, name, signature, superName, interfaces);
}
public String getClassName() {
return this.className;
}
public String getSuperName() {
return this.superName;
}
public byte[] toByteArray() {
return (byte[])((byte[])AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
byte[] b = ((ClassWriter)DebuggingClassWriter.access$001(DebuggingClassWriter.this)).toByteArray();
//如果有檔案位置則寫檔案
if (DebuggingClassWriter.debugLocation != null) {
String dirs = DebuggingClassWriter.this.className.replace('.', File.separatorChar);
try {
(new File(DebuggingClassWriter.debugLocation + File.separatorChar + dirs)).getParentFile().mkdirs();
File file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".class");
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
try {
out.write(b);
} finally {
out.close();
}
if (DebuggingClassWriter.traceCtor != null) {
file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".asm");
out = new BufferedOutputStream(new FileOutputStream(file));
try {
ClassReader cr = new ClassReader(b);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
ClassVisitor tcv = (ClassVisitor)DebuggingClassWriter.traceCtor.newInstance(null, pw);
cr.accept(tcv, 0);
pw.flush();
} finally {
out.close();
}
}
} catch (Exception var17) {
throw new CodeGenerationException(var17);
}
}
return b;
}
}));
}
可以通過
System.getProperty("cglib.debugLocation")
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/home/xxx");
通過設定可以寫檔案,寫道指定的路徑。
此處 通過寫位元組碼的方式實現了EnhancerKey子類,實現相關功能。這裡沒有註冊方法攔截器,因為是自己實現介面的實現類。
public void generateClass(ClassVisitor v) {
//繼承父類EnhancerKey
ClassEmitter ce = new ClassEmitter(v);
Method newInstance = ReflectUtils.findNewInstance(keyInterface);
if (!newInstance.getReturnType().equals(Object.class)) {
throw new IllegalArgumentException("newInstance method must return Object");
}
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);
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();
//屬性
List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class);
for (int i = 0; i < parameterTypes.length; i++) {
Type parameterType = parameterTypes[i];
Type fieldType = parameterType;
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
fieldType = customizer.getOutType(i, fieldType);
}
seed += fieldType.hashCode();
ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
getFieldName(i),
fieldType,
null);
e.dup();
e.load_arg(i);
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
customizer.customize(e, i, parameterType);
}
e.putfield(getFieldName(i));
}
e.return_value();
e.end_method();
// hash code
//方法
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, customizers);
}
e.return_value();
e.end_method();
// 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, customizers);
}
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, customizers);
}
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
e.return_value();
e.end_method();
ce.end_class();
}
3.2 示例的動態代理。
上面介紹了KeyFactory使用CGLIB的原始碼,下面是我們自己寫的類實現動態代理
Object result = super.create(key)//key就是上面CGLIB動態建立的KeyFactory物件。
原理跟KeyFactory一樣,只是generateClass實現不一樣
核心:註冊了方法攔截器,就是我們示例裡面
public class HelloCGLibProxy implements MethodInterceptor
public void generateClass(ClassVisitor v) throws Exception {
Class sc = (superclass == null) ? Object.class : superclass;
//final 類不能代理,因為CGLIB是通過繼承實現子類的方式達到動態代理的目的
if (TypeUtils.isFinal(sc.getModifiers()))
throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
//已定義的構造器
List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
//剔除相同的構造器
filterConstructors(sc, constructors);
// Order is very important: must add superclass, then
// its superclass chain, then each interface and
// its superinterfaces.
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) {
e.begin_class(Constants.V1_2,
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_2,
Constants.ACC_PUBLIC,
getClassName(),
null,
new Type[]{FACTORY},
Constants.SOURCE_FILE);
}
List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
//屬性
e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);
if (!interceptDuringConstruction) {
e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
}
e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
if (serialVersionUID != null) {
e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
}
for (int i = 0; i < callbackTypes.length; i++) {
e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
}
// This is declared private to avoid "public field" pollution
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動態代理功能依賴於方法攔截器實現
emitSetThreadCallbacks(e);
emitSetStaticCallbacks(e);
emitBindCallbacks(e);
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中生成了HelloService的代理類,此類事HelloService的子類。
4. 反編譯代理類
設定屬性
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "xxx");
有三個檔案,中間那個就是我們的代理類
通過繼承的方式來實現代理的
優點:可以代理類,代理速度快,生成位元組碼很慢,生成3個類
缺點:不能代理final類final方法