前言
JDK動態代理要求被代理的類必須實作介面,而生成的代理類也只能代理某個類介面定義的方法,這有很強的局限性,而CGLIB動態代理沒有這個要求,簡單來說,兩者的區別有以下幾點:
- Java動態代理只能夠對介面進行代理,不能對普通的類進行代理(因為所有生成的代理類的父類為Proxy,Java類繼承機制不允許多重繼承);CGLIB能夠代理普通類,
- ava動態代理使用Java原生的反射API進行操作,在生成類上比較高效;CGLIB使用ASM框架直接對位元組碼進行操作,在類的執行程序中比較高效,
一、舉個栗子
1.1 創建一個沒有實作任何介面的類
package com.leng.proxy.dynamic.cglib;
/**
* @Classname UserServiceImpl
* @Date 2020/9/22 21:58
* @Autor lengxuezhang
*/
public class UserServiceImpl {
public void login() {
System.out.println("用戶登錄......");
}
public void sayHello() {
System.out.println("Hello World!!!");
}
}
想實作對UserServiceImpl的動態代理,使用JDK動態代理是無法實作的,因為沒有實作介面,UserServiceImpl就是一個普通類,可以通過CGLIB實作代理,步驟如下:
- 首先實作一個
MethodInterceptor,方法呼叫會被轉發到該類的intercept()方法, - 然后在需要使用
UserServiceImpl的時候,通過CGLIB動態代理獲取代理物件,
1.2 實作MethodInterceptor介面
package com.leng.proxy.dynamic.cglib;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Date;
/**
* @Classname LogInterceptor
* @Date 2020/9/22 21:59
* @Autor lengxuezhang
*/
public class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(o, objects);
after();
return result;
}
// 預處理方法
private void before() {
System.out.println(String.format("log start time [%s] ", new Date()));
}
// 后處理方法
private void after() {
System.out.println(String.format("log end time [%s] ", new Date()));
}
}
intercept方法四個引數的含義如下:
obj: 代理類物件,
method: 被代理的類中的方法,
args: 呼叫方法需要的引數,
proxy: 生成的代理類對方法的“代理參考”,----?這句是什么意思?
用戶需要實作MethodInterceptor介面,實作對方法的攔截,這一點與JDK動態代理中用戶需要實作InvocationHandler介面類似,
1.3 客戶端中使用CGLIB
代碼如下:
package com.leng;
import com.leng.proxy.dynamic.cglib.LogInterceptor;
import com.leng.proxy.dynamic.cglib.UserServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
/**
* @Classname Client
* @Date 2020/9/12 2:40
* @Autor lengxuezhang
*/
public class Client {
public static void main(String[] args) {
//CGLIB加強器,用于生成代理物件,類比JDK的Proxy
Enhancer enhancer = new Enhancer();
//設定加強器繼承被代理類
enhancer.setSuperclass(UserServiceImpl.class);
//設定回呼
enhancer.setCallback(new LogInterceptor());
//生成代理類物件
UserServiceImpl userService = (UserServiceImpl) enhancer.create();
//呼叫代理類物件中的方法時,會被我們實作的方法攔截器所攔截
userService.login();
userService.sayHello();
}
}
Enhancer: Enhancer是CGLIB中最常用的一個類,和Java1.3動態代理中引入的Proxy類差不多,但和Proxy不同的是,Enhancer既能夠代理普通的class,也能夠代理介面,Enhancer創建一個被代理物件的子類并且攔截所有的方法呼叫(包括從Object中繼承的toString和hashCode方法),Enhancer不能攔截final方法,例如Object.getClass()方法,這是由于Java final方法語意決定的,基于同樣的道理,Enhancer也不能對fianl類進行代理操作,
Enhancer.setSuperclass用來設定父型別,Enhancer.create(Object…)方法是用來創建增強物件的,其提供了很多不同引數的方法用來匹配被增強類的不同構造方法,(雖然類的構造方法只是Java位元組碼層面的函式,但是Enhancer卻不能對其進行操作,Enhancer同樣不能操作static或者final類),我們也可以先使用Enhancer.createClass()來創建位元組碼(.class),然后用位元組碼動態的生成增強后的物件,
二、原始碼分析
2.1 生成指定類的Class物件位元組陣列
指定類是哪個類?
如上客戶端中的呼叫代碼,首先創建Enhancer物件,設定SuperClass父類(被代理類),然后呼叫Enhancer物件的create()方法,
這里對Enhancer類需要特別提出一點:Enhancer類也是AbstractClassGenerator的子類,用處后面遇到會詳細說,-
1. create()
/**
* 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();
}
private Object createHelper() {
//1.進行有效性驗證
//1.1 callBack不能為空,也就是說至少要有一個callBack(callBack與代理類緊密相關)
//1.2 有多個callBack時必須有callBackFilter
preValidate();
//2.先根據KEY_FACTORY 以當前代理類的配置資訊 生成一個組合Key,再利用這個組合Key,進行create
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;
//根據生成的key創建代理物件
Object result = super.create(key);
return result;
}
接下來來到AbstractClassGenerator類中的create方法,這一步就是為了得到動態類的Class物件(Class的物件,認作A),之后通過反射生成具體的類的物件(A的物件)
protected Object create(Object key) {
try {
//1.獲取當前類加載器,應用類加載器
ClassLoader loader = getClassLoader();
//2.快取,一級快取的key是類加載器,value是ClassLoaderData
//2.1 cache中有則直接獲取
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = https://www.cnblogs.com/cleverziv/archive/2020/10/01/cache.get(loader);
//2.2 cache中沒有則生成
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map newCache = new WeakHashMap(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
//3.呼叫 get方法獲取位元組碼,如果沒有位元組碼,則會創建位元組碼(Class物件)
Object obj = data.get(this, getUseCache());
//4.生成動態代理類
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
}
catch (RuntimeException | Error ex) {
throw ex;
}
catch (Exception ex) {
throw new CodeGenerationException(ex);
}
}
如代碼中的注釋,該方法的3、4是核心的步驟,首先詳細分析下3,我們進到get方法中
public Object get(AbstractClassGenerator gen, boolean useCache) {
//判斷是否開啟快取,可直接設定:enhancer.setUseCache(false);默認為true
if (!useCache) {
return gen.generate(ClassLoaderData.this);
}
else {
Object cachedValue = https://www.cnblogs.com/cleverziv/archive/2020/10/01/generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
關于 AbstractClassGenerator 的詳細決議,可參考:
死磕cglib系列之二 AbstractClassGenerator快取決議:https://blog.csdn.net/zhang6622056/article/details/87783480
這里我們直接來看generate方法
protected Class generate(ClassLoaderData data) {
Class gen;
Object save = CURRENT.get();
CURRENT.set(this);
try {
// 1.判斷有無classLoader
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.");
}
// 2.生成動態代理的類名
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
}
}
// 3.生成動態代理類的位元組碼
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
// 4.生成class檔案
synchronized (classLoader) { // just in case
// SPRING PATCH BEGIN
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);
// SPRING PATCH END
}
return gen;
}
catch (RuntimeException | Error ex) {
throw ex;
}
catch (Exception ex) {
throw new CodeGenerationException(ex);
}
finally {
CURRENT.set(save);
}
}
注釋中的3的方法是DefaultGeneratorStrategy中的方法如下:
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = this.getClassVisitor();
this.transform((ClassGenerator)cg).generateClass(cw);
return this.transform((byte[])cw.toByteArray());
}
注意,這里是一個訪問者模式,getClassVistor呼叫了asm的介面,生成了一個DebuggingClassWriter物件,注意這里的cg就是之前的Enhancer實體,它overrided generateClass方法,
于是此時查看generateClass方法,又回到Enhance類:
public void generateClass(ClassVisitor v) throws Exception {
Class sc = (superclass == null) ? Object.class : superclass;
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();
// 1.得到所有的方法,包括基類、介面
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);
}
});
// 2.生成位元組碼,引數還是之前的classWriter
// 2.1 這里的className就是之前生成的className
ClassEmitter e = new ClassEmitter(v);
if (currentData =https://www.cnblogs.com/cleverziv/archive/2020/10/01/= 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());
// 2.2 這些都是欄位,之后我們會在生成的檔案中看到
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);
}
// 2.4 這里就是生成的callback,命名就是CGLIB&CALLBACK_在陣列中的序號
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 =https://www.cnblogs.com/cleverziv/archive/2020/10/01/= null) {
// 2.5 filter在這里發生作用
emitMethods(e, methods, actualMethods);
emitConstructors(e, constructorInfo);
}
else {
emitDefaultConstructor(e);
}
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();
}
現在回到前面說到的“生成動態代理類物件”的方法:
//4.生成動態代理類
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
進到firstInstance方法,同樣是Enhancer類中
/**
* This method should not be called in regular flow.
* Technically speaking {@link #wrapCachedClass(Class)} uses {@link EnhancerFactoryData} as a cache value,
* and the latter enables faster instantiation than plain old reflection lookup and invoke.
* This method is left intact for backward compatibility reasons: just in case it was ever used.
* @param type class to instantiate
* @return newly created proxy instance
* @throws Exception if something goes wrong
*/
protected Object firstInstance(Class type) throws Exception {
if (classOnly) {
return type;
}
else {
// 從名字也能看出來是利用了反射來生成代理類物件的
return createUsingReflection(type);
}
}
使用到了ReflectUtils反射工具類中的方法,完成了動態代理物件的生成,
參考文獻:
https://www.cnblogs.com/cruze/p/3865180.html
https://blog.csdn.net/woshilijiuyi/article/details/83448407
https://www.jianshu.com/p/20203286ccd9
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/144788.html
標籤:其他
上一篇:學習第42天
下一篇:C#定義陣列并呈倒序排列
