最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的cglib原理解析

 更新時間:2023年10月23日 09:46:58   作者:bluespacezero  
這篇文章主要介紹了Java中的cglib原理解析,由于代理類繼承了被代理類,所以調(diào)用sayHello()方法時會直接調(diào)用代理類的sayHello()方法,而在代理類的方法中,調(diào)用了Callback的邏輯,需要的朋友可以參考下

cglib原理解析

先放上示例代碼:

//Person.java
public class Person {
    public void sayHello() {
        System.out.println("Hello!");
    }
}

//Test.java
import org.objectweb.asm.ClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.FileOutputStream;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Person.class);
        //設(shè)置生成的類不繼承Factory接口
        enhancer.setUseFactory(false);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("Intercept!");
                methodProxy.invokeSuper(o, objects);
                return null;
            }
        });

        Person person = (Person) enhancer.create();
        person.sayHello();

        //以下代碼是為了輸出cglib生成的類的class文件
        ClassWriter cw = new ClassWriter(0);
        enhancer.generateClass(cw);
        byte[] klass = cw.toByteArray();
        FileOutputStream fileOutputStream = new FileOutputStream(person.getClass().getName()+".class");
        fileOutputStream.write(klass);
        fileOutputStream.close();
    }
}

使用cglib生成代碼的過程很簡單:

  • new 一個Enhancer對象
  • 調(diào)用它的setSuperclass()方法設(shè)置需要代理的類
  • 調(diào)用它的setCallback()方法設(shè)置攔截被代理類方法時的邏輯

為了簡單起見,我們還調(diào)用了setUseFactory(false)方法,使得生成的代理類不實現(xiàn)Factory接口(該接口提供了一些生成新對象的和設(shè)置對象的Callback的方法)。并且沒有使用CallbackFilter。

cglib生成對象時主要的邏輯在Enchancer類的generateClass方法里面:

public void generateClass(ClassVisitor v) throws Exception {
        Class sc = (superclass == null) ? Object.class : superclass;

        //如果被代理類是final類型的,拋出異常
        if (TypeUtils.isFinal(sc.getModifiers()))
            throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
        //以下兩行代碼獲得被代理類的非私有構(gòu)造函數(shù)
        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();
        //得到被代理類及其父類、接口的非final、非static、非private方法。這些方法是需要代理的(在不考慮CallbackFilter的情況下)
        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) {
            //生成class文件的版本號、類的訪問描述符、類名、父類名、接口,并生成SourceFile屬性
            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());

        //以下生成代理類的字段,可以對照下面的反編譯結(jié)果觀看
        //生成private boolean CGLIB$BOUND字段
        e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
        //生成public static Object CGLIB$FACTORY_DATA字段
        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);
        }
        //生成private static final ThreadLocal CGLIB$THREAD_CALLBACKS字段
        e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
        //生成private static final Callback[] CGLIB$STATIC_CALLBACKS字段
        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);
        }

        //以下是生成Callback字段,可以看到,對應(yīng)每個設(shè)置的Callback,都會在代理類中生成一個對應(yīng)具體類型的字段
        for (int i = 0; i < callbackTypes.length; i++) {
            //在本例中生成的是private MethodInterceptor CGLIB$CALLBACK_0字段,后綴_0代表是在Enhancer中設(shè)置的第0個Callback
            e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
        }
        // This is declared private to avoid "public field" pollution
        //生成private static Object CGLIB$CALLBACK_FILTER字段。如果Enhancer只設(shè)置了一個Callback并且沒有設(shè)置CallbackFilter,那么會默認對該Enhancer對象添加一個指向第0個Callback的CallbackFilter
        e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);

        if (currentData == null) {
            //這個函數(shù)生成需要代理類的方法
            emitMethods(e, methods, actualMethods);
            //生成構(gòu)造函數(shù)
            emitConstructors(e, constructorInfo);
        } else {
            emitDefaultConstructor(e);
        }
        //以下三行代碼分別生成代理類的CGLIB$SET_THREAD_CALLBACKS、CGLIB$SET_STATIC_CALLBACKS和CGLIB$BIND_CALLBACKS函數(shù)
        emitSetThreadCallbacks(e);
        emitSetStaticCallbacks(e);
        emitBindCallbacks(e);

        if (useFactory || currentData != null) {
            int[] keys = getCallbackKeys();
            //如果useFactory為true就會生成幾個newInstance方法,還有幾個操作代理類的Callback的方法
            emitNewInstanceCallbacks(e);
            emitNewInstanceCallback(e);
            emitNewInstanceMultiarg(e, constructorInfo);
            emitGetCallback(e, keys);
            emitSetCallback(e, keys);
            emitGetCallbacks(e);
            emitSetCallbacks(e);
        }

        e.end_class();
    }

使用Bytecode Viewer的CFR反編譯生成的代理類如下:

/*
 * Decompiled with CFR 0_125.
 * 
 * Could not load the following classes:
 *  Person
 *  Person$$EnhancerByCGLIB$$34b905e4
 *  net.sf.cglib.core.ReflectUtils
 *  net.sf.cglib.core.Signature
 *  net.sf.cglib.proxy.Callback
 *  net.sf.cglib.proxy.MethodInterceptor
 *  net.sf.cglib.proxy.MethodProxy
 */
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.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
 * Exception performing whole class analysis ignored.
 */
public class Person$$EnhancerByCGLIB$$34b905e4
extends Person {
    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$sayHello$0$Method;
    private static final MethodProxy CGLIB$sayHello$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;
    static void CGLIB$STATICHOOK2() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class class_ = Class.forName("Person$$EnhancerByCGLIB$$34b905e4");
        Class class_2 = Class.forName("java.lang.Object");
        Method[] arrmethod = ReflectUtils.findMethods((String[])new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (Method[])class_2.getDeclaredMethods());
        CGLIB$equals$1$Method = arrmethod[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(class_2, class_, (String)"(Ljava/lang/Object;)Z", (String)"equals", (String)"CGLIB$equals$1");
        CGLIB$toString$2$Method = arrmethod[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/String;", (String)"toString", (String)"CGLIB$toString$2");
        CGLIB$hashCode$3$Method = arrmethod[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(class_2, class_, (String)"()I", (String)"hashCode", (String)"CGLIB$hashCode$3");
        CGLIB$clone$4$Method = arrmethod[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/Object;", (String)"clone", (String)"CGLIB$clone$4");
        class_2 = Class.forName("Person");
        CGLIB$sayHello$0$Method = ReflectUtils.findMethods((String[])new String[]{"sayHello", "()V"}, (Method[])class_2.getDeclaredMethods())[0];
        CGLIB$sayHello$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"sayHello", (String)"CGLIB$sayHello$0");
    }
    final void CGLIB$sayHello$0() {
        super.sayHello();
    }
    public final void sayHello() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept((Object)this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
            return;
        }
        super.sayHello();
    }
    final boolean CGLIB$equals$1(Object object) {
        return super.equals(object);
    }
    public final boolean equals(Object object) {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor == null) return super.equals(object);
        Object object2 = methodInterceptor.intercept((Object)this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);
        if (object2 == null) {
            return false;
        }
        boolean bl = (Boolean)object2;
        return bl;
    }
    final String CGLIB$toString$2() {
        return super.toString();
    }
    public final String toString() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor == null) return super.toString();
        return (String)methodInterceptor.intercept((Object)this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);
    }
    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }
    public final int hashCode() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor == null) return super.hashCode();
        Object object = methodInterceptor.intercept((Object)this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
        if (object == null) {
            return 0;
        }
        int n = ((Number)object).intValue();
        return n;
    }
    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }
    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor == null) return super.clone();
        return methodInterceptor.intercept((Object)this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
    }
    public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
        String string = signature.toString();
        switch (string.hashCode()) {
            case -508378822: {
                if (!string.equals("clone()Ljava/lang/Object;")) return null;
                return CGLIB$clone$4$Proxy;
            }
            case 1535311470: {
                if (!string.equals("sayHello()V")) return null;
                return CGLIB$sayHello$0$Proxy;
            }
            case 1826985398: {
                if (!string.equals("equals(Ljava/lang/Object;)Z")) return null;
                return CGLIB$equals$1$Proxy;
            }
            case 1913648695: {
                if (!string.equals("toString()Ljava/lang/String;")) return null;
                return CGLIB$toString$2$Proxy;
            }
            case 1984935277: {
                if (!string.equals("hashCode()I")) return null;
                return CGLIB$hashCode$3$Proxy;
            }
        }
        return null;
    }
    public Person$$EnhancerByCGLIB$$34b905e4() {
        Person$$EnhancerByCGLIB$$34b905e4 person$$EnhancerByCGLIB$$34b905e4 = this;
        Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)person$$EnhancerByCGLIB$$34b905e4);
    }
    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arrcallback) {
        CGLIB$THREAD_CALLBACKS.set(arrcallback);
    }
    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arrcallback) {
        CGLIB$STATIC_CALLBACKS = arrcallback;
    }
    private static final void CGLIB$BIND_CALLBACKS(Object object) {
        Person$$EnhancerByCGLIB$$34b905e4 person$$EnhancerByCGLIB$$34b905e4 = (Person$$EnhancerByCGLIB$$34b905e4)object;
        if (person$$EnhancerByCGLIB$$34b905e4.CGLIB$BOUND) return;
        person$$EnhancerByCGLIB$$34b905e4.CGLIB$BOUND = true;
        Object t = CGLIB$THREAD_CALLBACKS.get();
        if (t == null && (v783 = CGLIB$STATIC_CALLBACKS) == null) {
            return;
        }
        person$$EnhancerByCGLIB$$34b905e4.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])t)[0];
    }
    static {
        Person$$EnhancerByCGLIB$$34b905e4.CGLIB$STATICHOOK2();
    }
}

可以看到,在創(chuàng)建一個代理類的對象的時候,會先加載這個類,也就調(diào)用了類的靜態(tài)方法CGLIB$STATICHOOK2(),在這個函數(shù)中對類的其它靜態(tài)字段進行了初始化,比如對應(yīng)每個需要代理的方法都生成兩個字段,一個是用于反射的Method對象,另一個是用于加快方法調(diào)用、避免反射帶來的開銷的MethodProxy對象。然后在構(gòu)造函數(shù)里面調(diào)用了CGLIB$BIND_CALLBACKS(this),在CGLIB$BIND_CALLBACKS方法中會把private MethodInterceptor CGLIB$CALLBACK_0字段和設(shè)置的靜態(tài)變量ThreadLocal CGLIB$THREAD_CALLBACKS進行綁定,也就是說,設(shè)置的Callback并不是硬編碼在生成的代理類里面的,而是可以動態(tài)地設(shè)置。

由于代理類繼承了被代理類,所以調(diào)用sayHello()方法時會直接調(diào)用代理類的sayHello()方法,而在代理類的方法中,調(diào)用了Callback的邏輯。

到此這篇關(guān)于Java中的cglib原理解析的文章就介紹到這了,更多相關(guān)cglib原理解析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決SpringBoot中使用@Transactional注解遇到的問題

    解決SpringBoot中使用@Transactional注解遇到的問題

    這篇文章主要介紹了SpringBoot中使用@Transactional注解遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring Boot 靜態(tài)資源處理方式

    Spring Boot 靜態(tài)資源處理方式

    這篇文章主要介紹了Spring Boot 靜態(tài)資源處理方式,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-09-09
  • SpringBoot18 redis的配置方法

    SpringBoot18 redis的配置方法

    本文介紹在SpringBoot項目中集成和使用Redis的方法,包括添加依賴、配置文件、自定義序列化方式、使用方式、實際使用示例、常見操作總結(jié)以及注意事項,特別強調(diào)了配置類的作用,即使用JSON序列化以提高數(shù)據(jù)的可讀性、節(jié)省空間和跨語言兼容性,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • RocketMQ producer同步發(fā)送單向發(fā)送源碼解析

    RocketMQ producer同步發(fā)送單向發(fā)送源碼解析

    這篇文章主要為大家介紹了RocketMQ producer同步發(fā)送單向發(fā)送源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Java動態(tài)線程池插件dynamic-tp集成過程淺析

    Java動態(tài)線程池插件dynamic-tp集成過程淺析

    這篇文章主要介紹了Java動態(tài)線程池插件dynamic-tp集成過程,dynamic-tp是一個輕量級的動態(tài)線程池插件,它是一個基于配置中心的動態(tài)線程池,線程池的參數(shù)可以通過配置中心配置進行動態(tài)的修改
    2023-03-03
  • Java分布式事務(wù)實現(xiàn)原理與解決方案詳解

    Java分布式事務(wù)實現(xiàn)原理與解決方案詳解

    分布式事務(wù)是分布式系統(tǒng)中的核心挑戰(zhàn)之一,它確??缍鄠€獨立服務(wù)或數(shù)據(jù)源的操作能夠保持原子性、一致性、隔離性和持久性(ACID),本文給大家介紹Java生態(tài)中分布式事務(wù)的實現(xiàn)原理、主流解決方案及其適用場景,感興趣的朋友一起看看吧
    2025-09-09
  • Spring mvc攔截器實現(xiàn)原理解析

    Spring mvc攔截器實現(xiàn)原理解析

    這篇文章主要介紹了Spring mvc攔截器實現(xiàn)原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • JAVA時間戳-Calendar類使用(包括set,get,add方法)

    JAVA時間戳-Calendar類使用(包括set,get,add方法)

    這篇文章主要介紹了JAVA時間戳-Calendar類使用(包括set,get,add方法),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Java編碼輔助工具Lombok用法詳解

    Java編碼輔助工具Lombok用法詳解

    這篇文章主要介紹了Java編碼輔助工具Lombok用法詳解,可以使用Lombok來避免這種重復(fù)的操作,減少非核心代碼的臃腫,提高編碼效率,需要的朋友可以參考下
    2019-06-06
  • SpringBoot集成ECDH密鑰交換的方法

    SpringBoot集成ECDH密鑰交換的方法

    ECDH密鑰交換算法通過橢圓曲線和Diffie-Hellman方法生成共享密鑰,用于前端和后端之間的AES加密通信,前端使用elliptic.js生成密鑰對,后端使用crypto-js.min.js進行AES加密,本文給大家介紹SpringBoot集成ECDH密鑰交換的相關(guān)知識,感興趣的朋友一起看看吧
    2025-01-01

最新評論

蒙山县| 奉化市| 天津市| 彩票| 苍溪县| 酒泉市| 巴林右旗| 无极县| 灌南县| 富锦市| 景宁| 兖州市| 玛曲县| 乌拉特后旗| 安新县| 民权县| 盐边县| 九江县| 洱源县| 磴口县| 建水县| 岱山县| 东平县| 华安县| 喀喇| 肇源县| 新疆| 章丘市| 班戈县| 南雄市| 襄垣县| 吴江市| 织金县| 尉犁县| 湾仔区| 梓潼县| 赤水市| 赤城县| 新田县| 巫溪县| 揭东县|