cglib動(dòng)態(tài)代理源碼分析

一翘县、用法

1锈麸、普通類(lèi)

package com.suncy.article.article11.cglib;

public class Hello1{
   public void sayHi1() {
       System.out.println("hi1");
   }

   public void sayHi2() {
       System.out.println("hi2");
   }

   public void sayNo(){
       System.out.println("no");
   }
}

2薄翅、執(zhí)行代理對(duì)象方法的前后完成自己的操作

package com.suncy.article.article11.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    //需要代理的目標(biāo)對(duì)象
    private Object target;

    //重寫(xiě)攔截方法
    @Override
    public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable {
        System.out.println("cglib before");

        //方法執(zhí)行翘魄,參數(shù):target 目標(biāo)對(duì)象 arr參數(shù)數(shù)組
        Object invoke = method.invoke(target, arr);

        System.out.println("cglib after");
        return invoke;
    }

    //定義獲取代理對(duì)象方法
    public Object getCglibProxy(Object objectTarget) {
        //為目標(biāo)對(duì)象target賦值
        this.target = objectTarget;
        //同時(shí)可以在對(duì)應(yīng)目錄下找到.class文件
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\work\\tool\\");
        Enhancer enhancer = new Enhancer();

        //設(shè)置父類(lèi),因?yàn)镃glib是針對(duì)指定的類(lèi)生成一個(gè)子類(lèi),所以需要指定父類(lèi)
        enhancer.setSuperclass(objectTarget.getClass());

        // 設(shè)置回調(diào)
        enhancer.setCallback(this);

        //創(chuàng)建并返回代理對(duì)象
        Object result = enhancer.create();
        return result;
    }
}

3但荤、使用

package com.suncy.article.article11.cglib;

public class CglibTest {
    public static void main(String[] args) {
        //實(shí)例化CglibProxy對(duì)象
        CglibProxy cglib = new CglibProxy();
        //獲取代理對(duì)象
        Hello1 hello1 =  (Hello1) cglib.getCglibProxy(new Hello1());
        //調(diào)用代理對(duì)象方法
        hello1.sayHi1();
        System.out.println("==========");
        hello1.sayHi2();
        System.out.println("==========");
        hello1.sayNo();
    }
}

4桑包、測(cè)試結(jié)果

image.png

5、結(jié)果說(shuō)明

cglib是將被代理類(lèi)所有的方法都進(jìn)行了攔截垒手,加上了我們自定義的操作科贬。

二榜掌、源碼分析

關(guān)鍵點(diǎn)

setSuperclass和setCallback都屬于賦值操作憎账,所以關(guān)鍵點(diǎn)在于enhancer.create()方法,這個(gè)方法的作用是:生成代理對(duì)象反砌。

Enhancer enhancer = new Enhancer();

//設(shè)置父類(lèi),因?yàn)镃glib是針對(duì)指定的類(lèi)生成一個(gè)子類(lèi)宴树,所以需要指定父類(lèi)
enhancer.setSuperclass(objectTarget.getClass());

// 設(shè)置回調(diào)
enhancer.setCallback(this);

//創(chuàng)建并返回代理對(duì)象
Object result = enhancer.create();

//返回代理對(duì)象
return result;

1、enhancer.create()

public Object create() {
    classOnly = false;
    argumentTypes = null;
    return createHelper();
}

2锭吨、進(jìn)入createHelper()方法
先是生成了一個(gè)key零如,然后調(diào)用了父類(lèi)的create方法埠况。

private Object createHelper() {
    preValidate();
    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;
    Object result = super.create(key);
    return result;
}

3、super.create(key)

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);
    }
}

到這個(gè)方法,我們需要打個(gè)斷點(diǎn)壁榕,調(diào)試一下牌里,看一下返回值走到的是哪個(gè)。


image.png

也就是說(shuō)态辛,通過(guò)firstInstance((Class) obj) 方法返回了一個(gè)代理對(duì)象,而這個(gè)方法的入?yún)⑹焓罚覀儼l(fā)現(xiàn)是一個(gè)Class以故,那現(xiàn)在就需要去找到這個(gè)Class的淶源怒详。
4、找到Class obj的淶源
簡(jiǎn)化代碼如下:

data = new ClassLoaderData(loader);
Object obj = data.get(this, getUseCache());

也就是說(shuō)這個(gè)obj是通過(guò)調(diào)用data的get方法來(lái)的静尼,那么我們?nèi)フ乙幌逻@個(gè)get方法鼠渺。

5鹃祖、data.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);
            }
        }

我們需要打個(gè)斷點(diǎn)恬口,找到進(jìn)入的是哪個(gè)代碼塊


image.png

6、generatedClasses.get()方法
別忘了這個(gè)方法返回的對(duì)象是一個(gè)Class

    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);
    }

7、createEntry(key, cacheKey, v)方法

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);
                }
            });
            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;
    }

這個(gè)函數(shù)也比較長(zhǎng),簡(jiǎn)化一下

task = new FutureTask<V>(new Callable<V>() {
                public V call() throws Exception {
                    return loader.apply(key);
                }
            });
result = task.get();
return result;

繼續(xù)打個(gè)斷點(diǎn)看一下


image.png

繼續(xù)進(jìn)入


image.png

到這個(gè)地方基本上說(shuō)明我們通過(guò)generatedClasses.get()方法,拿到的東西就是通過(guò)這個(gè) gen.generate(ClassLoaderData.this)返回的。

8提岔、generate方法

 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
                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);
        }
    }

我們發(fā)現(xiàn)有兩個(gè)關(guān)鍵的地方夯巷,簡(jiǎn)化一下

byte[] b = strategy.generate(this);
 if (protectionDomain == null) {
     gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
     gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
 }
return gen;

9趁餐、strategy.generate(this)方法
我們發(fā)現(xiàn)這個(gè)方法返回的是一堆byte[]后雷,可以大膽猜測(cè)勉抓,這堆byte就是生成的代理類(lèi)的字節(jié)碼的詳細(xì)數(shù)據(jù)藕筋。

    public byte[] generate(ClassGenerator cg) throws Exception {
        DebuggingClassWriter cw = getClassVisitor();
        transform(cg).generateClass(cw);
        return transform(cw.toByteArray());
    }

打個(gè)斷點(diǎn)


我們發(fā)現(xiàn)generateClass走到的是KeyFactory里的generateClass方法

10、KeyFactory的generateClass方法

  public void generateClass(ClassVisitor v) {
            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_8,
                           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();
        }

11、transform(cw.toByteArray())
查看返回值:return transform(cw.toByteArray());
這個(gè)toByteArray方法就是獲得了一堆byte

public byte[] toByteArray() {
        
      return (byte[]) java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction() {
            public Object run() {
                byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
                if (debugLocation != null) {
                    String dirs = className.replace('.', File.separatorChar);
                    try {
                        new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
                        
                        File file = new File(new File(debugLocation), dirs + ".class");
                        OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
                        try {
                            out.write(b);
                        } finally {
                            out.close();
                        }
                        
                        if (traceCtor != null) {
                            file = new File(new File(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)traceCtor.newInstance(new Object[]{null, pw});
                                cr.accept(tcv, 0);
                                pw.flush();
                            } finally {
                                out.close();
                            }
                        }
                    } catch (Exception e) {
                        throw new CodeGenerationException(e);
                    }
                }
                return b;
             }  
            });
        }

其實(shí)到這個(gè)地方,我們已經(jīng)能明白cglib代理與jdk代理的相似的地方,那就是都需要先手動(dòng)構(gòu)造出一個(gè)類(lèi)的完整的字節(jié)碼數(shù)據(jù)儒恋,然后將這堆字節(jié)碼數(shù)據(jù)加載成為.class文件诫尽,之后通過(guò)反射生成代理對(duì)象炬守。

三牧嫉、查看代理對(duì)象的結(jié)構(gòu)

1、生成代理Class文件

以下設(shè)置將生成的.class文件放入到了tool目錄下

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\work\\tool\\");

如圖所示


image.png

2减途、查看反編譯后的Class代碼

下載并安裝JD-GUI工具酣藻、打開(kāi),并將文件拖入即可

package com.suncy.article.article11.cglib;

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 Hello1$$EnhancerByCGLIB$$3c92030b extends Hello1 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$sayHi1$0$Method;
  
  private static final MethodProxy CGLIB$sayHi1$0$Proxy;
  
  private static final Object[] CGLIB$emptyArgs;
  
  private static final Method CGLIB$sayHi2$1$Method;
  
  private static final MethodProxy CGLIB$sayHi2$1$Proxy;
  
  private static final Method CGLIB$sayNo$2$Method;
  
  private static final MethodProxy CGLIB$sayNo$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<?> clazz1 = Class.forName("com.suncy.article.article11.cglib.Hello1$$EnhancerByCGLIB$$3c92030b");
    Class<?> clazz2;
    CGLIB$sayHi1$0$Method = ReflectUtils.findMethods(new String[] { "sayHi1", "()V", "sayHi2", "()V", "sayNo", "()V" }, (clazz2 = Class.forName("com.suncy.article.article11.cglib.Hello1")).getDeclaredMethods())[0];
    CGLIB$sayHi1$0$Proxy = MethodProxy.create(clazz2, clazz1, "()V", "sayHi1", "CGLIB$sayHi1$0");
    CGLIB$sayHi2$1$Method = ReflectUtils.findMethods(new String[] { "sayHi1", "()V", "sayHi2", "()V", "sayNo", "()V" }, (clazz2 = Class.forName("com.suncy.article.article11.cglib.Hello1")).getDeclaredMethods())[1];
    CGLIB$sayHi2$1$Proxy = MethodProxy.create(clazz2, clazz1, "()V", "sayHi2", "CGLIB$sayHi2$1");
    CGLIB$sayNo$2$Method = ReflectUtils.findMethods(new String[] { "sayHi1", "()V", "sayHi2", "()V", "sayNo", "()V" }, (clazz2 = Class.forName("com.suncy.article.article11.cglib.Hello1")).getDeclaredMethods())[2];
    CGLIB$sayNo$2$Proxy = MethodProxy.create(clazz2, clazz1, "()V", "sayNo", "CGLIB$sayNo$2");
    ReflectUtils.findMethods(new String[] { "sayHi1", "()V", "sayHi2", "()V", "sayNo", "()V" }, (clazz2 = Class.forName("com.suncy.article.article11.cglib.Hello1")).getDeclaredMethods());
    CGLIB$equals$3$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[0];
    CGLIB$equals$3$Proxy = MethodProxy.create(clazz2, clazz1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
    CGLIB$toString$4$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[1];
    CGLIB$toString$4$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
    CGLIB$hashCode$5$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[2];
    CGLIB$hashCode$5$Proxy = MethodProxy.create(clazz2, clazz1, "()I", "hashCode", "CGLIB$hashCode$5");
    CGLIB$clone$6$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[3];
    CGLIB$clone$6$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
    ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods());
  }
  
  final void CGLIB$sayHi1$0() {
    super.sayHi1();
  }
  
  public final void sayHi1() {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null)
      return; 
    super.sayHi1();
  }
  
  final void CGLIB$sayHi2$1() {
    super.sayHi2();
  }
  
  public final void sayHi2() {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null)
      return; 
    super.sayHi2();
  }
  
  final void CGLIB$sayNo$2() {
    super.sayNo();
  }
  
  public final void sayNo() {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null)
      return; 
    super.sayNo();
  }
  
  final boolean CGLIB$equals$3(Object paramObject) {
    return super.equals(paramObject);
  }
  
  public final boolean equals(Object paramObject) {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null) {
      this.CGLIB$CALLBACK_0.intercept(this, CGLIB$equals$3$Method, new Object[] { paramObject }, CGLIB$equals$3$Proxy);
      return (this.CGLIB$CALLBACK_0.intercept(this, CGLIB$equals$3$Method, new Object[] { paramObject }, CGLIB$equals$3$Proxy) == null) ? false : ((Boolean)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$equals$3$Method, new Object[] { paramObject }, CGLIB$equals$3$Proxy)).booleanValue();
    } 
    return super.equals(paramObject);
  }
  
  final String CGLIB$toString$4() {
    return super.toString();
  }
  
  public final String toString() {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    return (this.CGLIB$CALLBACK_0 != null) ? (String)this.CGLIB$CALLBACK_0.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() {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null) {
      this.CGLIB$CALLBACK_0.intercept(this, CGLIB$hashCode$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy);
      return (this.CGLIB$CALLBACK_0.intercept(this, CGLIB$hashCode$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy) == null) ? 0 : ((Number)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$hashCode$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy)).intValue();
    } 
    return super.hashCode();
  }
  
  final Object CGLIB$clone$6() throws CloneNotSupportedException {
    return super.clone();
  }
  
  protected final Object clone() throws CloneNotSupportedException {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    return (this.CGLIB$CALLBACK_0 != null) ? this.CGLIB$CALLBACK_0.intercept(this, CGLIB$clone$6$Method, CGLIB$emptyArgs, CGLIB$clone$6$Proxy) : super.clone();
  }
  
  public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature) {
    // Byte code:
    //   0: aload_0
    //   1: invokevirtual toString : ()Ljava/lang/String;
    //   4: dup
    //   5: invokevirtual hashCode : ()I
    //   8: lookupswitch default -> 160, -2007222039 -> 76, -508378822 -> 88, 1826985398 -> 100, 1913648695 -> 112, 1984935277 -> 124, 2023576048 -> 136, 2023605839 -> 148
    //   76: ldc 'sayNo()V'
    //   78: invokevirtual equals : (Ljava/lang/Object;)Z
    //   81: ifeq -> 161
    //   84: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$sayNo$2$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   87: areturn
    //   88: ldc 'clone()Ljava/lang/Object;'
    //   90: invokevirtual equals : (Ljava/lang/Object;)Z
    //   93: ifeq -> 161
    //   96: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$clone$6$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   99: areturn
    //   100: ldc 'equals(Ljava/lang/Object;)Z'
    //   102: invokevirtual equals : (Ljava/lang/Object;)Z
    //   105: ifeq -> 161
    //   108: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$equals$3$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   111: areturn
    //   112: ldc 'toString()Ljava/lang/String;'
    //   114: invokevirtual equals : (Ljava/lang/Object;)Z
    //   117: ifeq -> 161
    //   120: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$toString$4$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   123: areturn
    //   124: ldc 'hashCode()I'
    //   126: invokevirtual equals : (Ljava/lang/Object;)Z
    //   129: ifeq -> 161
    //   132: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$hashCode$5$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   135: areturn
    //   136: ldc 'sayHi1()V'
    //   138: invokevirtual equals : (Ljava/lang/Object;)Z
    //   141: ifeq -> 161
    //   144: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$sayHi1$0$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   147: areturn
    //   148: ldc 'sayHi2()V'
    //   150: invokevirtual equals : (Ljava/lang/Object;)Z
    //   153: ifeq -> 161
    //   156: getstatic com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$sayHi2$1$Proxy : Lnet/sf/cglib/proxy/MethodProxy;
    //   159: areturn
    //   160: pop
    //   161: aconst_null
    //   162: areturn
  }
  
  public Hello1$$EnhancerByCGLIB$$3c92030b() {
    CGLIB$BIND_CALLBACKS(this);
  }
  
  public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback) {
    CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
  }
  
  public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback) {
    CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
  }
  
  private static final void CGLIB$BIND_CALLBACKS(Object paramObject) {
    Hello1$$EnhancerByCGLIB$$3c92030b hello1$$EnhancerByCGLIB$$3c92030b = (Hello1$$EnhancerByCGLIB$$3c92030b)paramObject;
    if (!hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$BOUND) {
      hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$BOUND = true;
      if (CGLIB$THREAD_CALLBACKS.get() == null) {
        CGLIB$THREAD_CALLBACKS.get();
        if (CGLIB$STATIC_CALLBACKS == null)
          return; 
      } 
      hello1$$EnhancerByCGLIB$$3c92030b.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])CGLIB$THREAD_CALLBACKS.get())[0];
    } 
  }
  
  public Object newInstance(Callback[] paramArrayOfCallback) {
    CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
    CGLIB$SET_THREAD_CALLBACKS(null);
    return new Hello1$$EnhancerByCGLIB$$3c92030b();
  }
  
  public Object newInstance(Callback paramCallback) {
    CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
    CGLIB$SET_THREAD_CALLBACKS(null);
    return new Hello1$$EnhancerByCGLIB$$3c92030b();
  }
  
  public Object newInstance(Class[] paramArrayOfClass, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback) {
    // Byte code:
    //   0: aload_3
    //   1: invokestatic CGLIB$SET_THREAD_CALLBACKS : ([Lnet/sf/cglib/proxy/Callback;)V
    //   4: new com/suncy/article/article11/cglib/Hello1$$EnhancerByCGLIB$$3c92030b
    //   7: dup
    //   8: aload_1
    //   9: dup
    //   10: arraylength
    //   11: tableswitch default -> 35, 0 -> 28
    //   28: pop
    //   29: invokespecial <init> : ()V
    //   32: goto -> 49
    //   35: goto -> 38
    //   38: pop
    //   39: new java/lang/IllegalArgumentException
    //   42: dup
    //   43: ldc 'Constructor not found'
    //   45: invokespecial <init> : (Ljava/lang/String;)V
    //   48: athrow
    //   49: aconst_null
    //   50: invokestatic CGLIB$SET_THREAD_CALLBACKS : ([Lnet/sf/cglib/proxy/Callback;)V
    //   53: areturn
  }
  
  public Callback getCallback(int paramInt) {
    CGLIB$BIND_CALLBACKS(this);
    switch (paramInt) {
      case 0:
      
    } 
    return null;
  }
  
  public void setCallback(int paramInt, Callback paramCallback) {
    switch (paramInt) {
      case 0:
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)paramCallback;
        break;
    } 
  }
  
  public Callback[] getCallbacks() {
    CGLIB$BIND_CALLBACKS(this);
    return new Callback[] { (Callback)this.CGLIB$CALLBACK_0 };
  }
  
  public void setCallbacks(Callback[] paramArrayOfCallback) {
    this.CGLIB$CALLBACK_0 = (MethodInterceptor)paramArrayOfCallback[0];
  }
  
  static {
    CGLIB$STATICHOOK1();
  }
}

3臊恋、與jdk代理的區(qū)別

(1)jdk代理繼承了Proxy,墓捻,由于java是單繼承抖仅,所以只能通過(guò)接口方式進(jìn)行代理坊夫。
(2)cglib是繼承了被代理的對(duì)象,重寫(xiě)了所有的方法撤卢。

四环凿、說(shuō)明

到這里,我們僅僅是知道了cglib的大概邏輯放吩,要想清楚的了解它是怎么樣生成這堆字節(jié)碼文件的智听,還需要更深入的了解字節(jié)碼的結(jié)構(gòu)和ASM(java的字節(jié)碼操縱框架)的用法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市渡紫,隨后出現(xiàn)的幾起案子到推,更是在濱河造成了極大的恐慌,老刑警劉巖惕澎,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莉测,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡唧喉,警方通過(guò)查閱死者的電腦和手機(jī)捣卤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)八孝,“玉大人董朝,你說(shuō)我怎么就攤上這事「甚耍” “怎么了子姜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)楼入。 經(jīng)常有香客問(wèn)我闲询,道長(zhǎng),這世上最難降的妖魔是什么浅辙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任扭弧,我火速辦了婚禮,結(jié)果婚禮上记舆,老公的妹妹穿的比我還像新娘鸽捻。我一直安慰自己,他們只是感情好泽腮,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布御蒲。 她就那樣靜靜地躺著,像睡著了一般诊赊。 火紅的嫁衣襯著肌膚如雪厚满。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天碧磅,我揣著相機(jī)與錄音碘箍,去河邊找鬼遵馆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛丰榴,可吹牛的內(nèi)容都是我干的货邓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼四濒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼换况!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起盗蟆,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤戈二,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后喳资,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體觉吭,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年骨饿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亏栈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片台腥。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宏赘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出黎侈,到底是詐尸還是另有隱情察署,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布峻汉,位于F島的核電站贴汪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏休吠。R本人自食惡果不足惜扳埂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘤礁。 院中可真熱鬧阳懂,春花似錦、人聲如沸柜思。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赡盘。三九已至号枕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陨享,已是汗流浹背葱淳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工钝腺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛙紫。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓拍屑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親坑傅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子僵驰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容