扯淡 祝各位在園裡的朋友新年快樂! 辛苦一年,為更好的自己也為更好的世界,很多人要感謝你們,你們也應該有很多人要感謝吧。 看了馬斯克的採訪視頻,又想起 "蘭迪·鮑許的最後一課" ,時光遷移,唯有夢想可堅持。 概念 在java的世界里,基於jvm實現的語言最終要進入jvm編譯的流程都需要把上層高級語言 ...
扯淡
祝各位在園裡的朋友新年快樂!
辛苦一年,為更好的自己也為更好的世界,很多人要感謝你們,你們也應該有很多人要感謝吧。
看了馬斯克的採訪視頻,又想起蘭迪·鮑許的最後一課,時光遷移,唯有夢想可堅持。
概念
在java的世界里,基於jvm實現的語言最終要進入jvm編譯的流程都需要把上層高級語言所表達的內容自行編譯成位元組碼文件,而cglib是一個操作位元組碼生成自定義類的庫,它底層調用的是ASM庫來操作位元組碼的。示意圖:
這裡主要以使用cglib入口為起點進入它源代碼,詳細查看內部的實現機制。
具體實現流程
AbstractClassGenerator是CGLIB 核心類,這個抽象類作為CGLIB中代碼生成調度員角色,做了緩存,定製ClassLoader,命名。
Enhancer 繼承 AbstractClassGenerator
從Enhancer中的crate方法系列開始這場旅行。
以下三個方法用classOnly參數來控制返回的是Class對象,還是代理對象本身。所以我們可以知道在調用createHelper方法的時候這兩個對象是要生成的。
/**
*
* 入口方法,產生一個代理對象
* @return a new instance
*/
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
public Object create(Class[] argumentTypes, Object[] arguments) {
classOnly = false;
if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) {
throw new IllegalArgumentException("Arguments must be non-null and of equal length");
}
this.argumentTypes = argumentTypes;
this.arguments = arguments;
return createHelper();
}
public Class createClass() {
classOnly = true;
return (Class)createHelper();
}
靜態的crate方法:
public static Object create(Class type, Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(type);
e.setCallback(callback);
return e.create();
}
public static Object create(Class superclass, Class interfaces[], Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(superclass);
e.setInterfaces(interfaces);
e.setCallback(callback);
return e.create();
}
public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
Enhancer e = new Enhancer();
e.setSuperclass(superclass);
e.setInterfaces(interfaces);
e.setCallbackFilter(filter);
e.setCallbacks(callbacks);
return e.create();
}
都是new 一個Enhancer然後進行操作,最後都調用create()方法,提供給外部調用者不同的調用方式,我們可以看到至多需要以下幾個元素:
- Class superclass
- Class[] interfaces
- CallbackFilter filter
- Callback[] callbacks
那麼最後這些方法在設置好變數後,都會調用到createHelper()方法:
private Object createHelper() {
// 校驗
preValidate();
// 生成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;
// 調用AbstractClassGenerator.create(Object)方法
Object result = super.create(key);
return result;
}
AbstractClassGenerator.create(Object)方法:
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;
// 這裡產生class對象 背後有做緩存功能
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
// 模版方法 用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);
}
}
abstract protected Object firstInstance(Class type) throws Exception;
abstract protected Object nextInstance(Object instance) throws Exception;
我們看到firstInstance 和 nextInstance模版方法給子類實現,
而在進入執行子類模版方法前,代理類的class位元組碼必然已經組裝好了。
Object obj = data.get(this, getUseCache());
這行獲取class實例或者EnhancerFactoryData,返回的類型也是判斷執行firstInstance 或 nextInstance的依據。這裡就是組裝類位元組碼,緩存類信息等操作的入口。後續展開
先看一下看Enhancer的兩個實例化入口的實現:
protected Object firstInstance(Class type) throws Exception {
if (classOnly) {
return type;
} else {
return createUsingReflection(type);
}
}
protected Object nextInstance(Object instance) {
EnhancerFactoryData data = (EnhancerFactoryData) instance;
if (classOnly) {
return data.generatedClass;
}
Class[] argumentTypes = this.argumentTypes;
Object[] arguments = this.arguments;
if (argumentTypes == null) {
argumentTypes = Constants.EMPTY_CLASS_ARRAY;
arguments = null;
}
return data.newInstance(argumentTypes, arguments, callbacks);
}
classOnly欄位控制返回類型,從代碼實現上來看nextInstance是firstInstance的升級版,在firstInstance上的原文註釋上我們也可以印證,實際自定義代理類在創建時是不會調用到firstInstance而是調用nextInstance,而nextInstance中是做類一個緩存功能。
而我們可以查看上面連個方法要實例化出對象最終都會調用到ReflectUtils.newInstance(final Constructor cstruct, final Object[] args)方法。查看方法我們發現是用cstruct.newInstance(args)這行代碼來實現的:
public static Object newInstance(final Constructor cstruct, final Object[] args) {
boolean flag = cstruct.isAccessible();
try {
if (!flag) {
cstruct.setAccessible(true);
}
// 最終調用 產生代理對象
Object result = cstruct.newInstance(args);
return result;
} catch (InstantiationException e) {
throw new CodeGenerationException(e);
} catch (IllegalAccessException e) {
throw new CodeGenerationException(e);
} catch (InvocationTargetException e) {
throw new CodeGenerationException(e.getTargetException());
} finally {
if (!flag) {
cstruct.setAccessible(flag);
}
}
}
傳入nextInstance方法的是EnhancerFactoryData實例。 EnhancerFactoryData中保存了以下這些內容:
public final Class generatedClass;
private final Method setThreadCallbacks;
private final Class[] primaryConstructorArgTypes;
private final Constructor primaryConstructor;
到這裡我們就明白了nextInstance是firstInstance升級版的意義,就是把Constructor緩存起來在每次要實例化時不需要像firstInstance那樣調用下麵的代碼去遍歷出Constructor:
public static Constructor getConstructor(Class type, Class[] parameterTypes) {
try {
// 這一步就是nextInstance在省略的
Constructor constructor = type.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
return constructor;
} catch (NoSuchMethodException e) {
throw new CodeGenerationException(e);
}
}
前面提到Object obj = data.get(this, getUseCache());返回組裝好位元組碼的代理類或包裝類EnhancerFactoryData,用於實例化代理類。
調用到AbstractClassGenerator中的內部類ClassLoaderData的方法get:
public Object get(AbstractClassGenerator gen, boolean useCache) {
if (!useCache) {
return gen.generate(ClassLoaderData.this);
} else {
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
從上面的代碼有不使用緩存的邏輯就直接調用AbstractClassGenerator.generate(ClassLoaderData data)方法。看名字就知道這個是核心方法了,而用走緩存分支肯定也是要調這個方法,只是多了一份緩存的邏輯。
generatedClasses 是一個LoadingCache類,這個LoadingCache是用於存儲的設計類:
// 實際存儲map
protected final ConcurrentMap<KK, Object> map;
protected final Function<K, V> loader;
// 名字是map 其實是封裝了獲得kk的演算法 獲取是調用apply方法
protected final Function<K, KK> keyMapper;
Function類是一個函數介面(Functional Interface):
public interface Function<K, V> {
V apply(K key);
}
可以理解為帶某個自定義演算法的類,可以傳送給其他類使用。
LoadingCache類中的核心方法get(K key)(其中key後續進行詳細分析),最終會調用到createEntry,:
public V get(K key) {
// 包裝key的演算法
final KK cacheKey = keyMapper.apply(key);
Object v = map.get(cacheKey);
// 如果是FutureTask 則說明還在創建中,如果不是FutureTask,則說明已經創建好可直接返回
if (v != null && !(v instanceof FutureTask)) {
return (V) v;
}
return createEntry(key, cacheKey, v);
}
protected V createEntry(final K key, KK cacheKey, Object v) {
FutureTask<V> task;
// 標記是一個新建的流程
boolean creator = false;
// v有值說明是已經找到在執行的FutureTask
if (v != null) {
// Another thread is already loading an instance
task = (FutureTask<V>) v;
} else {
//新建一個FutureTask
task = new FutureTask<V>(new Callable<V>() {
public V call() throws Exception {
// task執行內容
return loader.apply(key);
}
});
// putIfAbsent判斷是否已經有值
Object prevTask = map.putIfAbsent(cacheKey, task);
// 三種情況
// 1,沒值 則是新放的task 就啟動這個task
// 2,有值 是FutureTask 說明有線程在我執行putIfAbsent之前已經捷足先登了 那就把自己新建的task拋棄掉
// 3,有值 不是FutureTask 說明已經有task已經執行完成並放入了result 那就直接返回這個resutl即可
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 {
// task執行完畢返回值
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;
}
}
以上代碼詳細解讀後發現是這樣設計的:
1,用ConcurrentMap存儲,先放的value是FutureTask,執行完成後value放執行結果,並保證在FutureTask放入之後,再不能進行替換操作,無論是否執行完畢。
2,利用FutureTask非同步獲取執行結果的能力把編織位元組碼的過程非同步化,新的線程獲取同一個代理類時,因為保證在放入map後的task只執行一次,也就沒有併發情況是多個相同代理類的編織消耗了。
下麵畫了示意圖:
這個設計的場景應該是比較常見的,產生一個對象比較消耗,這時候自然會想到把它緩存起來,一般的寫法就向下麵的代碼:
先組裝這個對象,然後放入緩存,放入的時候判斷是否已存在。但是這種寫法在高併發時一波線程全部同時到達第一步代碼,然後都去執行消耗的代碼,然後進入第二步的時候就要不斷替換,雖然最後的結果可能是正確的,不過會有無謂的浪費。現在再看一下cglib的實現就可以學到了。
Object object = create();//1
map.putIfAbsent(key, obj);//2
這裡詳細再展開下,因為這也是非常值得學習的地方,我們想如果我們並不想用非同步的方式呢?以下是一個網上解決方案,很有意思:
public class concurrentMapTest {
// 記錄自旋狀態的輕量級類,只封裝了一個volatile狀態
public static class SpinStatus{
volatile boolean released;
}
// 輔助併發控制的Map,用來找出每個key對應的第一個成功進入的線程
private ConcurrentMap<String, SpinStatus> raceUtil = new ConcurrentHashMap<String, SpinStatus>();
private ConcurrentMap<String, Object> map = new ConcurrentHashMap<String, Object>();
public Object test(String key){
Object value = map.get(key);
// 第一次
if(value == null){
// 需要為併發的線程new一個自旋狀態,只有第一個成功執行putIfAbsent方法的線程設置的SpinStatus會被共用
SpinStatus spinStatus = new SpinStatus();
SpinStatus oldSpinStatus = raceUtil.putIfAbsent(key, spinStatus);
//只有第一個執行成功的線程拿到的oldSpinStatus是null,其他線程拿到的oldSpinStatus是第一個線程設置的,可以在所有線程中共用
if(oldSpinStatus == null){
value = create();
// 放入共用的併發Map,後續線程執行get()方法後可以直接拿到非null的引用返回
map.put(key, value);
// 釋放其他自旋的線程,註意,對第一個成功執行的線程使用的是spinStatus的引用
spinStatus.released = true;
}else{
// 其他線程在oldSpinStatus引用所指向的共用自旋狀態上自旋,等待被釋放
while(!oldSpinStatus.released){};
}
// 再次獲取一下,這時候是肯定不為空
value = map.get(key);
}
return value;
}
/**
* 假裝耗時代碼
* @return
*/
public static String create(){
return "1";
}
}
新建task的代碼就是組裝代理類的代碼,但是這個return loader.apply(key);里的load是調用方傳入的,我們看下調用方的代碼:
先打開ClassLoaderData的代碼,它是AbstractClassGenerator的內部類:
protected static class ClassLoaderData {
private final Set<String> reservedClassNames = new HashSet<String>();
private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;
private final WeakReference<ClassLoader> classLoader;
private final Predicate uniqueNamePredicate = new Predicate() {
public boolean evaluate(Object name) {
return reservedClassNames.contains(name);
}
};
private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
return gen.key;
}
};
public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
}
this.classLoader = new WeakReference<ClassLoader>(classLoader);
// 組裝load
Function<AbstractClassGenerator, Object> load =
new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this);
return gen.wrapCachedClass(klass);
}
};
// 組裝LoadingCache代碼
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}
public ClassLoader getClassLoader() {
return classLoader.get();
}
public void reserveName(String name) {
reservedClassNames.add(name);
}
public Predicate getUniqueNamePredicate() {
return uniqueNamePredicate;
}
public Object get(AbstractClassGenerator gen, boolean useCache) {
if (!useCache) {
return gen.generate(ClassLoaderData.this);
} else {
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
}
直接取出loader.apply(key);的代碼:
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this);
return gen.wrapCachedClass(klass);
}
首先調用的是
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
}
}
// 調用strategy的generate
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
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);
}
}
調用strategy的generate:
public byte[] generate(ClassGenerator cg) throws Exception {
// DebuggingClassWriter中DEBUG_LOCATION_PROPERTY可以設置代理類class文件的路徑
DebuggingClassWriter cw = getClassVisitor();
transform(cg).generateClass(cw);
return transform(cw.toByteArray());
}
最後還是調用到net.sf.cglib.proxy.Enhancer#generateClass 而這個方法是ClassGenerator介面定義要實現的方法。
因為在Enhancer中已經保存了編織代理類的全部信息,編織過程的入口由自己來實現。這裡就不再繼續深入研究位元組碼編織的過程,因為這需要理解asm的api和class文件格式已經jvm編譯規範。後續的學習過程中將補全這部分內容。
那麼至此基本寫完類以cglib產生代理類的主流程。
反編譯例子
以下是一個例子附加了代理類的反編譯代碼:
被代理類:
public class SampleClass {
public String test(String input) {
return "Hello world!";
}
public void big(String i){
System.out.println("1111");
}
public int test1(String input) {
return 1;
}
}
操作類:
public void testMethodInterceptor() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
return "Hello cglib!";
} else {
return proxy.invokeSuper(obj, args);
}
}
});
SampleClass proxy = (SampleClass) enhancer.create();
}
我們可以通過下麵代碼的設置將cglib產生的代理類生成到自定義的路徑上去,方便自己反編譯:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/gitwork/");
反編譯後代碼,我們可以直接看到它繼承了SampleClass類,然後在test方法實現的地方做了處理:
package com.hope.learn.third.cglib;
import com.hope.learn.third.cglib.SampleClass;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class SampleClass$$EnhancerByCGLIB$$a2b2935d extends SampleClass implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$test$0$Method;
private static final MethodProxy CGLIB$test$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$big$1$Method;
private static final MethodProxy CGLIB$big$1$Proxy;
private static final Method CGLIB$test1$2$Method;
private static final MethodProxy CGLIB$test1$2$Proxy;
private static final Method CGLIB$equals$3$Method;
private static final MethodProxy CGLIB$equals$3$Proxy;
private static final Method CGLIB$toString$4$Method;
private static final MethodProxy CGLIB$toString$4$Proxy;
private static final Method CGLIB$hashCode$5$Method;
private static final MethodProxy CGLIB$hashCode$5$Proxy;
private static final Method CGLIB$clone$6$Method;
private static final MethodProxy CGLIB$clone$6$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.hope.learn.third.cglib.SampleClass$$EnhancerByCGLIB$$a2b2935d");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"test", "(Ljava/lang/String;)Ljava/lang/String;", "big", "(Ljava/lang/String;)V", "test1", "(Ljava/lang/String;)I"}, (var1 = Class.forName("com.hope.learn.third.cglib.SampleClass")).getDeclaredMethods());
CGLIB$test$0$Method = var10000[0];
CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "test", "CGLIB$test$0");
CGLIB$big$1$Method = var10000[1];
CGLIB$big$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "big", "CGLIB$big$1");
CGLIB$test1$2$Method = var10000[2];
CGLIB$test1$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)I", "test1", "CGLIB$test1$2");
var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$3$Method = var10000[0];
CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
CGLIB$toString$4$Method = var10000[1];
CGLIB$toString$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
CGLIB$hashCode$5$Method = var10000[2];
CGLIB$hashCode$5$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$5");
CGLIB$clone$6$Method = var10000[3];
CGLIB$clone$6$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
}
final String CGLIB$test$0(String var1) {
return super.test(var1);
}
public final String test(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null?(String)var10000.intercept(this, CGLIB$test$0$Method, new Object[]{var1}, CGLIB$test$0$Proxy):super.test(var1);
}
final void CGLIB$big$1(String var1) {
super.big(var1);
}
public final void big(String var1) {
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$big$1$Method, new Object[]{var1}, CGLIB$big$1$Proxy);
} else {
super.big(var1);
}
}
final int CGLIB$test1$2(String var1) {
return super.test1(var1);
}
public final int test1(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if(var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$test1$2$Method, new Object[]{var1}, CGLIB$test1$2$Proxy);
return var2 == null?0:((Number)var2).intValue();
} else {
return super.test1(var1);
}
}
final boolean CGLIB$equals$3(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if(var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$3$Method, new Object[]{var1}, CGLIB$equals$3$Proxy);
return var2 == null?false:((Boolean)var2).booleanValue();
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$4() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$4$Method, CGLIB$emptyArgs, CGLIB$toString$4$Proxy):super.toString();
}
final int CGLIB$hashCode$5() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if(var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy);
return var1 == null?0:((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$6() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null?var10000.intercept(this, CGLIB$clone$6$Method, CGLIB$emptyArgs, CGLIB$clone$6$Proxy):super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1315810049:
if(var10000.equals("big(Ljava/lang/String;)V")) {
return CGLIB$big$1$Proxy;
}
break;
case -508378822:
if(var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$6$Proxy;
}
break;
case -178329709:
if(var10000.equals("test(Ljava/lang/String;)Ljava/lang/String;")) {
return CGLIB$test$0$Proxy;
}
break;
case 992023923:
if(var10000.equals("test1(Ljava/lang/String;)I")) {
return CGLIB$test1$2$Proxy;
}
break;
case 1826985398:
if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$3$Proxy;
}
break;
case 1913648695:
if(var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$4$Proxy;
}
break;
case 1984935277:
if(var10000.equals("hashCode()I")) {
return CGLIB$hashCode$5$Proxy;
}
}
return null;
}
public SampleClass$$EnhancerByCGLIB$$a2b2935d() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
SampleClass$$EnhancerByCGLIB$$a2b2935d var1 = (SampleClass$$EnhancerByCGLIB$$a2b2935d)var0;
if(!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if(var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if(CGLIB$STATIC_CALLBACKS == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
SampleClass$$EnhancerByCGLIB$$a2b2935d var10000 = new SampleClass$$EnhancerByCGLIB$$a2b2935d();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
SampleClass$$EnhancerByCGLIB$$a2b2935d var10000 = new SampleClass$$EnhancerByCGLIB$$a2b2935d();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
SampleClass$$EnhancerByCGLIB$$a2b2935d var10000 = new SampleClass$$EnhancerByCGLIB$$a2b2935d;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
原文git更新地址
讓我們繼續前行
努力不一定成功,但不努力肯定不會成功。