CGLIB动态代理底层实现原理

cglib底层源码分析(⼆) 其实我们如果看到了cglib所⽣成的代理类之后,其实就不难猜测,cglib是如何去⽣成代理类了,我们看 ⼀个完整的代理类: 我们发现,UserService代理类既继承了UserService类,也实现了Factory接⼝,从⽽代理中就需要去 实现Factory接⼝中的⼏个⽅法: 我们可以发现newInstance()⽅法会重新⽣成⼀个代理对象,setCallbacks()和getCallbacks()可以⽤来 设置或获取增强逻辑。 我们还发现,不仅只... 阅读详情

一、前言

  最近在探究Spring AOP的性能,发现最后是绕不开JDK动态代理和CGLIB动态代理这两个点。笔者心里大致有这么个概念:对于动态代理来说,CGLIB性能要好于JDK。也知道CGLIB是利用ASM技术基于继承子类实现动态代理,JDK是基于实现接口实现动态代理,但是对于底层实现还是比较模糊。今天就彻底整明白CGLIB动态代理的底层实现。

二、前置准备

(一)测试代码

CGLIB核心的几个概念:

  • 被代理对象,本案例【Dog】
  • 方法拦截器MethodInterceptor,本案例【CglibMethodInterceptor】
  • Enhance代理对象生成工具,本案例【TestMain测试主类中创建】
1. 自定义方法拦截器CglibMethodInterceptor

  后面也会将MethodInterceptor说成Callback,其实是一个东西,MethodInterceptor是实现了Callback接口的。

/**
 * 方法拦截器,不用依赖被代理业务类的引用
 */
public class CglibMethodInterceptor implements MethodInterceptor {

    /**
     * 功能主要是在调用业务类方法之前 之后添加统计时间的方法逻辑.
     * intercept 因为具有 MethodProxy methodProxy 参数的原因,不再需要代理类的引用对象了,直接通过 methodProxy 对象访问被代理对象的方法(这种方式更快)。
     * 当然 也可以通过反射机制,通过 method 引用实例    Object result = method.invoke(target, args); 形式反射调用被代理类方法,
     * target 实例代表被代理类对象引用, 初始化 CglibMethodInterceptor 时候被赋值 。但是Cglib不推荐使用这种方式
     *
     * @param object      代表Cglib 生成的动态代理类 对象本身
     * @param method      代理类中被拦截的接口方法 Method 实例
     * @param args        接口方法参数
     * @param methodProxy 用于调用父类真正的业务类方法。可以直接调用被代理类接口方法
     * @return 被代理类方法执行返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        MonitorUtil.start();
        Object result = methodProxy.invokeSuper(object, args);
//        Object result = methodProxy.invoke(object, args);
        System.out.println("after");
        MonitorUtil.finish(method.getName());
        return result;
    }
}
2. 被代理类
public class Dog {

    public String call() {
        System.out.println("wang wang wang");
        return "Dog ..";
    }
 }
3. 切面方法
/**
 * 方法用时监控类,作为一个切面 ,具有两个方法
 */
public class MonitorUtil {

    private static final ThreadLocal<Long> tl = new ThreadLocal<>();

    public static void start() {
        tl.set(System.currentTimeMillis());
    }

    /**
     * 结束时打印耗时
     * @param methodName 监控方法名
     */
    public static void finish(String methodName) {
        long finishTime = System.currentTimeMillis();
        System.out.println(methodName + "方法执行耗时" + (finishTime - tl.get()) + "ms");
    }
}
4. 测试主类
public class TestMain {

    /**
     * 用于生成 Cglib 动态代理类工具方法
     * @param target 代表需要 被代理的 委托类的 Class 对象
     * @return 代理类对象
     */
    public static Object cglibProxyGenerator(Class target) {
        // 创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        // 为代理类指定需要代理的类,也即是父类
        enhancer.setSuperclass(target);
        // 设置方法拦截器回调引用,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept() 方法进行拦截
        enhancer.setCallback(new CglibMethodInterceptor());
        // 创建cglib 代理类
        return enhancer.create();
    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "classFiles");
        Dog poolDog = (Dog) cglibProxyGenerator(Dog.class);
        poolDog.call();

    }
}

(二)CGLIB生成的子类

  Dog$$EnhancerByCGLIB$$beb9d601

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.allen.testDynamicProxy.cglibProxy;

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;

// 实现net.sf.cglib.proxy.Factory的目的是提供一些创建代理对象实例的工厂方法,这些方法会比反射创建对象快【clazz.newInstance()】
public class Dog$$EnhancerByCGLIB$$beb9d601 extends Dog 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;
    // Dog类call的Method对象
    private static final Method CGLIB$call$0$Method;
    // Dog类call方法的代理对象
    private static final MethodProxy CGLIB$call$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    // Object类equals方法的Method对象
    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;

    /**
     * CGLIB$call$0$Method和CGLIB$call$0$Proxy就是MethodInterceptor接口的入参
     * MethodProxy 比 Method反射调用方法更快
     */
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        // 加载生成的增强类
        Class var0 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog$$EnhancerByCGLIB$$beb9d601");
        Class var1;
        // 通过反射获取Object类的Method对象
        Method[] 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$1$Method = var10000[0];
        // 为 Method 创建对应的 MethodProxy 对象
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        // Dog类call方法Method对象
        CGLIB$call$0$Method = ReflectUtils.findMethods(new String[]{"call", "()Ljava/lang/String;"}, (var1 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog")).getDeclaredMethods())[0];
        CGLIB$call$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "call", "CGLIB$call$0");
    }

    final String CGLIB$call$0() {
        return super.call();
    }
    // 重写 Dog类的call方法,添加CallBack回调【即执行MethodInterceptor的intercept方法,即我们自定义的CglibMethodInterceptor的intercept方法】
    public final String call() {
        // 这边获取MethodInterceptor为null
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            // 重新绑定MethodInterceptor
            CGLIB$BIND_CALLBACKS(this);
            // 这边还是null
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$call$0$Method, CGLIB$emptyArgs, CGLIB$call$0$Proxy) : super.call();
    }

    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$2() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 371634473:
            if (var10000.equals("call()Ljava/lang/String;")) {
                return CGLIB$call$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }

        return null;
    }

    // 实例化构造方法会绑定CallBacks
    public Dog$$EnhancerByCGLIB$$beb9d601() {
        CGLIB$BIND_CALLBACKS(this);
    }

    // 设置CallBack到ThreadLocal
    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;
    }
    /**
     * 判断并绑定CallBack对象【就是MethodInterceptor对象,也即自定义的CglibMethodInterceptor】
     */
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        Dog$$EnhancerByCGLIB$$beb9d601 var1 = (Dog$$EnhancerByCGLIB$$beb9d601)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }
    /**
     * 使用无参构造方法创建增强后的子类新实例
     * @param callbacks 多个MethodInterceptor对象数组
     * @return new instance of the same type
     */ 
    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        Dog$$EnhancerByCGLIB$$beb9d601 var10000 = new Dog$$EnhancerByCGLIB$$beb9d601();
        // 将ThreadLocal的 CallBacks 至空
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
    /**
     * 使用无参构造方法创建增强后的子类新实例
     * 该对象只能指定一个Callback【MethodInterceptor】
     * @param callback 自定义的MethodInterceptor对象
     * @return new instance of the same type
     */
    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        Dog$$EnhancerByCGLIB$$beb9d601 var10000 = new Dog$$EnhancerByCGLIB$$beb9d601();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
    /** 本案例中,实例化增强子类的时候就是调用此方法
     * @param types 构造方法参数类型
     * @param args 构造方法参数
     * @param callbacks 多个CallBack对象数组
     * @return new instance of the same type
     */
    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        Dog$$EnhancerByCGLIB$$beb9d601 var10000 = new Dog$$EnhancerByCGLIB$$beb9d601;
        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();
    }
}

(三)CGLIB生成的FastClass-1【简称f1】

  Dog$$FastClassByCGLIB$$7ac19ed7

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.allen.testDynamicProxy.cglibProxy;

import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

public class Dog$$FastClassByCGLIB$$7ac19ed7 extends FastClass {
    public Dog$$FastClassByCGLIB$$7ac19ed7(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case 371634473:
            if (var10000.equals("call()Ljava/lang/String;")) {
                return 0;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 1;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 2;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 3;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 1;
                    }
                }
            }
            break;
        case 3045982:
            if (var1.equals("call")) {
                switch(var2.length) {
                case 0:
                    return 0;
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 3;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        Dog var10000 = (Dog)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                return var10000.call();
            case 1:
                return new Boolean(var10000.equals(var3[0]));
            case 2:
                return var10000.toString();
            case 3:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        Dog var10000 = new Dog;
        Dog var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 3;
    }
}

(四)CGLIB生成的FastClass-2【简称f2】

  Dog$$EnhancerByCGLIB$$beb9d601$$FastClassByCGLIB$$916924fc

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.allen.testDynamicProxy.cglibProxy;

import com.allen.testDynamicProxy.cglibProxy.Dog..EnhancerByCGLIB..beb9d601;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;

public class Dog$$EnhancerByCGLIB$$beb9d601$$FastClassByCGLIB$$916924fc extends FastClass {
    public Dog$$EnhancerByCGLIB$$beb9d601$$FastClassByCGLIB$$916924fc(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -2055565910:
            if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 1;
            }
            break;
        case -1882565338:
            if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
                return 4;
            }
            break;
        case -1457535688:
            if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                return 8;
            }
            break;
        case -1411842725:
            if (var10000.equals("CGLIB$hashCode$3()I")) {
                return 6;
            }
            break;
        case -1212270792:
            if (var10000.equals("CGLIB$call$0()Ljava/lang/String;")) {
                return 5;
            }
            break;
        case -894172689:
            if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 20;
            }
            break;
        case -623122092:
            if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
                return 13;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return 17;
            }
            break;
        case -419626537:
            if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 9;
            }
            break;
        case 371634473:
            if (var10000.equals("call()Ljava/lang/String;")) {
                return 2;
            }
            break;
        case 560567118:
            if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
                return 12;
            }
            break;
        case 811063227:
            if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 19;
            }
            break;
        case 973717575:
            if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
                return 11;
            }
            break;
        case 1221173700:
            if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 18;
            }
            break;
        case 1230699260:
            if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
                return 10;
            }
            break;
        case 1306468936:
            if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) {
                return 3;
            }
            break;
        case 1584330438:
            if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 0;
            }
            break;
        case 1800494055:
            if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
                return 7;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 14;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 15;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 16;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 15;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 14;
                    }
                }
            }
            break;
        case -1053468136:
            if (var1.equals("getCallbacks")) {
                switch(var2.length) {
                case 0:
                    return 11;
                }
            }
            break;
        case -124978609:
            if (var1.equals("CGLIB$equals$1")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 4;
                    }
                }
            }
            break;
        case -60403779:
            if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 0;
                    }
                }
            }
            break;
        case -29025555:
            if (var1.equals("CGLIB$hashCode$3")) {
                switch(var2.length) {
                case 0:
                    return 6;
                }
            }
            break;
        case 3045982:
            if (var1.equals("call")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        case 52714989:
            if (var1.equals("CGLIB$call$0")) {
                switch(var2.length) {
                case 0:
                    return 5;
                }
            }
            break;
        case 85179481:
            if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 1;
                    }
                }
            }
            break;
        case 94756189:
            if (var1.equals("clone")) {
                switch(var2.length) {
                case 0:
                    return 17;
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 16;
                }
            }
            break;
        case 161998109:
            if (var1.equals("CGLIB$STATICHOOK1")) {
                switch(var2.length) {
                case 0:
                    return 8;
                }
            }
            break;
        case 495524492:
            if (var1.equals("setCallbacks")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 9;
                    }
                }
            }
            break;
        case 1154623345:
            if (var1.equals("CGLIB$findMethodProxy")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
                        return 13;
                    }
                }
            }
            break;
        case 1543336189:
            if (var1.equals("CGLIB$toString$2")) {
                switch(var2.length) {
                case 0:
                    return 3;
                }
            }
            break;
        case 1811874389:
            if (var1.equals("newInstance")) {
                switch(var2.length) {
                case 1:
                    String var10001 = var2[0].getName();
                    switch(var10001.hashCode()) {
                    case -845341380:
                        if (var10001.equals("net.sf.cglib.proxy.Callback")) {
                            return 20;
                        }
                        break;
                    case 1730110032:
                        if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
                            return 18;
                        }
                    }
                case 2:
                default:
                    break;
                case 3:
                    if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 19;
                    }
                }
            }
            break;
        case 1817099975:
            if (var1.equals("setCallback")) {
                switch(var2.length) {
                case 2:
                    if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
                        return 12;
                    }
                }
            }
            break;
        case 1905679803:
            if (var1.equals("getCallback")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("int")) {
                        return 10;
                    }
                }
            }
            break;
        case 1951977610:
            if (var1.equals("CGLIB$clone$4")) {
                switch(var2.length) {
                case 0:
                    return 7;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        beb9d601 var10000 = (beb9d601)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                beb9d601.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 1:
                beb9d601.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 2:
                return var10000.call();
            case 3:
                return var10000.CGLIB$toString$2();
            case 4:
                return new Boolean(var10000.CGLIB$equals$1(var3[0]));
            case 5:
                return var10000.CGLIB$call$0();
            case 6:
                return new Integer(var10000.CGLIB$hashCode$3());
            case 7:
                return var10000.CGLIB$clone$4();
            case 8:
                beb9d601.CGLIB$STATICHOOK1();
                return null;
            case 9:
                var10000.setCallbacks((Callback[])var3[0]);
                return null;
            case 10:
                return var10000.getCallback(((Number)var3[0]).intValue());
            case 11:
                return var10000.getCallbacks();
            case 12:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                return null;
            case 13:
                return beb9d601.CGLIB$findMethodProxy((Signature)var3[0]);
            case 14:
                return new Boolean(var10000.equals(var3[0]));
            case 15:
                return var10000.toString();
            case 16:
                return new Integer(var10000.hashCode());
            case 17:
                return var10000.clone();
            case 18:
                return var10000.newInstance((Callback[])var3[0]);
            case 19:
                return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
            case 20:
                return var10000.newInstance((Callback)var3[0]);
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        beb9d601 var10000 = new beb9d601;
        beb9d601 var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 20;
    }
}

三、CGLIB代理类创建流程

  代理类的创建主要是在enhancer.create()方法调用后进行的,大致流程如下:

image.png

(一)代理类的创建

  首先看下在实例化代理类期间绑定Callback的过程「即自定义的MethodInterceptor」,核心源码【net.sf.cglib.proxy.Enhancer.EnhancerFactoryData#newInstance】:image.png

注意这边的setThreadCallbacks是个final类型的变量,会在EnhancerFactoryData的构造方法中赋值为代理类Dog$$EnhancerByCGLIB$$beb9d601的SET_THREAD_CALLBACKS方法对象,对应的SET_THREAD_CALLBACKS源码如下:

// 设置CallBack到ThreadLocal
    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        // CGLIB$THREAD_CALLBACKS是个final static变量,在代理类的静态代码块中赋值为ThreadLocal()
        // 代理类的静态代码块下面会讲到
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

  代理类Dog$$EnhancerByCGLIB$$beb9d601类加载的时候,会执行代理类的静态方法块,期间会给每个被代理类Dog的成员方法创建一个MethdProxy代理方法对象。

(二)创建MethodProxy

  MethodProxy封装了原始Dog类的方法签名【sig1】,对应代理类方法的签名【sig2】以及代理类的一些创建信息【原始类和代理类的名称、类生成策略等等】。对应的代理类的静态代码块内容如下:

// CGLIB$call$0$Method和CGLIB$call$0$Proxy就是MethodInterceptor接口的入参
static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        // 加载生成的增强类
        Class var0 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog$$EnhancerByCGLIB$$beb9d601");
        Class var1;
        // 通过反射获取Object类的Method对象
        Method[] 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$1$Method = var10000[0];
        // 为 Method 创建对应的 MethodProxy 对象
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        // Dog类call方法Method对象
        CGLIB$call$0$Method = ReflectUtils.findMethods(new String[]{"call", "()Ljava/lang/String;"}, (var1 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog")).getDeclaredMethods())[0];
        // var1: 被代理类  var0:代理类
        CGLIB$call$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "call", "CGLIB$call$0");
    }

  对应MethodProxy.create()【net.sf.cglib.proxy.MethodProxy#creat()】方法:

/**
     * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
     * for similar functionality.
     * @param c1 被代理类
     * @param c2 代理类
     * @param desc 方法描述【"()Ljava/lang/String;"】
     * @param name1 方法1名称【"call"】
     * @param name2 方法2名称【"CGLIB$call$0"】
     */
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        MethodProxy proxy = new MethodProxy();
        // 构建方法签名
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }

关于方法签名的debug信息【后面会用这个方法签名在Fastclass中查询对应的index索引】:sig1-2.png

(三)创建CreateInfo

  CreateInfo是MethodProxy的一个内部类,主要保存代理类的一些创建信息。

private static class CreateInfo
    {    
        // 对应Dog原始类
        Class c1;
        // 代理类Dog$$EnhancerByCGLIB$$beb9d601
        Class c2;
        // 代理类命名策略
        NamingPolicy namingPolicy;
        // 代理类生成策略
        GeneratorStrategy strategy;
        boolean attemptLoad;
        
        public CreateInfo(Class c1, Class c2)
        {
            this.c1 = c1;
            this.c2 = c2;
            AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
            if (fromEnhancer != null) {
                namingPolicy = fromEnhancer.getNamingPolicy();
                strategy = fromEnhancer.getStrategy();
                attemptLoad = fromEnhancer.getAttemptLoad();
            }
        }
    }

四、CGLIB动态代理调用流程

  当执行目标方法时,代理对象调用流程如下:image.png

相信看完上面的流程图,基本就对CGLIB的底层实现有了大致的概念。当然下面我还会进行详细分析。

(一)重写父类方法

  基于一开始的demo,笔者从调用目标方法一步步分析。⚠️main方法调用poolDog.call();时,实际上执行的是代理对象的call()方法,代理对象的生成已经在上一节分析过了。那我们直接看代理对象的call()方法,源码如下:

/**
     * 重写 Dog类的call方法,添加CallBack回调
     * 【即执行MethodInterceptor的intercept方法,即我们自定义的  CglibMethodInterceptor的intercept方法】 
     */
    public final String call() {
        // 从成员属性CGLIB$CALLBACK_0获取MethodInterceptor
        // 第一次调用是null,进入下面的if逻辑
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            // 重新绑定MethodInterceptor,并赋值给成员属性CGLIB$CALLBACK_0
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        // @param this 代理对象本身
        // @param CGLIB$call$0$Method Dog类call方法Method对象【静态代码块已赋值】
        // @param CGLIB$emptyArgs Dog类call方法参数【我这边是void,所以没有】
        // @param CGLIB$call$0$Proxy Dog类call方法的代理方法对象【静态代码块已赋值】
        return var10000 != null ? (String)var10000.intercept(this, CGLIB$call$0$Method, CGLIB$emptyArgs, CGLIB$call$0$Proxy) : super.call();
    }

    /**
     * 判断并绑定CallBack对象【就是MethodInterceptor对象,也即自定义的CglibMethodInterceptor】
     */
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        // var0即代理类当前对象,将其对象的引用指向var1
        Dog$$EnhancerByCGLIB$$beb9d601 var1 = (Dog$$EnhancerByCGLIB$$beb9d601)var0;
        // 这边判断是true,创建代理类的时候通过反射已将对应的Callback设置到ThreadLocal
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            // 将ThreadLocal中的Callback赋值给var10000
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }
            // 将Callback赋值给成员属性CGLIB$CALLBACK_0
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

当调用代理对象重写过的call()方法时,会执行对应的方法拦截器,即我们自定义的MethodInterceptor中intercept方法的逻辑【本案例中对应自定义拦截器类CglibMethodInterceptor】,对应intercept方法的传参和含义在上面的代码注释中已说明。

(二)原始父类方法的匹配调用

  接下来,在MethodInterceptor的intercept方法中调用的methodProxy.invokeSuper(object, args);时,最终就会执行父类Dog的call()方法。具体怎么调用执行的,先看MethodProxy.invokeSuper(object, args);的执行逻辑,源码如下:

/**
     * 调用CGLIB增强的父类目标方法
     * @param obj the enhanced object, must be the object passed as the first
     * argument to the MethodInterceptor
     * @param args the arguments passed to the intercepted method; you may substitute a different
     * argument array as long as the types are compatible
     * @see MethodInterceptor#intercept
     * @throws Throwable the bare exceptions thrown by the called method are passed through
     * without wrapping in an <code>InvocationTargetException</code>
     */
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            // 初始化辅助数据
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
1. init()方法

  在上面的流程图中我们也大致能看到init()方法干了些什么事。主要是在处理FastClass,FastClass是什么?
简单理解,FastClass是代理对象方法 到 被代理对象方法的映射【对应FastClass的源码已在前置准备中贴出】。
⚠️init()方法只会在第一次被调用的时候去执行FastClass创建等操作。

1)先看下init()方法源码:
private void init()
    {
        /* 
         * Using a volatile invariant allows us to initialize the FastClass and
         * method index pairs atomically.
         * 
         * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
         * code could allow fastClassInfo to be instantiated more than once, which
         * appears to be benign.
         */
        if (fastClassInfo == null)
        {
            synchronized (initLock)
            {
                if (fastClassInfo == null)
                {
                    // 获取代理类的创建信息【上面有提过】
                    CreateInfo ci = createInfo;
                    // 新建FastClassInfo对象
                    FastClassInfo fci = new FastClassInfo();
                    // 生成FastClass f1,并赋值给FastClassInfo的成员属性
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    // 根据方法签名,获取代理类中对应call方法在f1中的索引
                    fci.i1 = fci.f1.getIndex(sig1);
                    // 根据方法签名,获取代理类中对应call方法在f2中的索引
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                    createInfo = null;
                }
            }
        }
    }

/* 
 * FastClassInfo也是MethodProxy的一个内部类
 */
private static class FastClassInfo
    {
        // 对应前置准备中的f1
        FastClass f1;
        // 对应前置准备中的f2
        FastClass f2;
        int i1;
        int i2;
    }

init()方法其实就是创建了两个FastClass,然后建立FastClass 到 代理对象 关于 目标方法 的 索引。

2)fci.f2.invoke(fci.i2, obj, args);

  invoke的传参说明:

  • i2: 获取代理类中对应call方法在f2中的索引
  • obj: 代理对象本身
  • args: 目标方法的传参

f2中invoke部分源码:image.png

接下就会调用代理对象对应的方法:image.png

看到这是不是有点明了了,最后这不就是执行了我们父类Dog的call()方法吗。那整个核心的实现逻辑和调用流程大致就是这样的。

(三)CGLIB死循环了

  上面一小节关于目标方法的调用是通过net.sf.cglib.proxy.MethodProxy#invokeSuper完成的,CGLIB中还有一个net.sf.cglib.proxy.MethodProxy#invoke。在自定义的MethodProxy中,将invokeSuper改成invoke,运行一下,报错了,无限递归导致栈溢出。
  在解释原因之前,有没有发现一个问题,前面不是生成了两个FastClass吗,截止现在我们只用到了一个。你的猜想正确,invoke方法就是用的f1中的索引。
  死循环的问题我这边不详细解释,以一张图说明【其中的元素信息完全基于前置准备的代码,同学们可以自己本地写个demo尝试】:

image.png

五、性能:CGLIB vs JDK

  其实说实话,工作中并没有说单单就因为将动态代理模式从JDK换成CGLIB,性能就有明显提升的情况,大部分情况性能相差不多。但是明显CGLIB适用性更广,SpringBoot将AOP的动态代理默认设置成了CGLIB,我想估计也不是性能使然。
  理论上说,针对JDK动态代理的Method.invoke()和CGLIB的MethodProxy.invokeSuper()这两个invoke来说,CGLIB感觉更加优雅些,但是刚开始第一次调用CGLIB是比较慢的,还记得上面提到的init()吗。非要钻牛角尖说CGLIB性能更好的话,可能是MethodAccessor的锅。

Method.invoke(target,params),实际是 MethodAccessor实例真正完成反射调用。Java 版本的 MethodAccessorImpl 调用效率比 Native 版本要快 20 倍以上,但是 Java 版本加载时要比 Native 多消耗 3-4 倍资源,所以默认会调用 Native 版本,如果调用次数超过 15 次以后,就会选择运行效率更高的 Java 版本。但是⚠️:存放method的 reflectionData是 SoftReference的,即在某些内存比较苛刻的情况下是可能被回收的【通过 -XX:SoftRefLRUPolicyMSPerMB这个参数来控制回收的时机】。一旦回收,就需要调用 getDeclaredMethods0 进行遍历查找,重新缓存。

关于JDK代理的细节,可以参考我之前的文章:https://www.heapdump.cn/artic...

  over,希望这篇吐血肝货,可以帮你理解CGLIB底层实现原理。继续肝💪·····


cglib底层源码分析(⼀) cglib是⼀种动态代理技术,可以针对类来⽣成⼀个代理对象。 ⽐如,我们现有⼀个UserService类: 现在利⽤cglib对UserService类中的test()⽅法进⾏增强: 在分析底层源码实现之前,我们先来试试,cglib能否代理接⼝,定义⼀个UserInterface接⼝ 然后利⽤cglib来代理⼀个接⼝: 也是可以正常运⾏的,那么⽤cglib代理⼀个类和代理⼀个接⼝的底层有什么区别呢?我们继续分析。 我们知道,既然要⽣成⼀个代理对象,那么就肯定需要⼀个代理... 阅读详情

相关推荐

【保姆级】手把手捋动态代理流程(JDK+Cglib超详细源码分析)

动态代理,通俗点说就是:无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。从而避免了静态代理那样需要声明大量的代理类。上面的简介中提到了两个关键的名词:“静态代理”和“动态代理”我们先来看来下两个问题:首先什么是代理呢?它可以看作是对最终调用目标的一个封装,可以通过操作代理对象来调用目标类,这样就可以实现调用者和目标对象的解耦合“静态代理”和“动态代理”又有什么区别呢?

aqin1012的博客 23万+

CGLIB动态代理详解分析

CGLIB是强大的、高性能的代码生成库,被广泛应用于AOP框架,它底层使用ASM来操作字节码生成新的类,为对象引入间接级别,以控制对象的访问。CGLIB相比于JDK动态代理更加强大,JDK动态代理只能对接口进行代理,而CGLIB既可以代理普通类,也能够代理接口。

weixin_43397326的博客 6586

JDK与CGLIB动态代理原理及底层实现深度解析

动态代理作为Java反射机制与设计模式结合的典范,广泛应用于AOP编程、事务管理、日志记录、权限控制等场景。其核心思想是在运行时动态生成代理对象,从而在不修改目标类源码的前提下,实现对方法调用的拦截与增强。相较于静态代理,动态代理具有更高的灵活性和扩展性,支持运行时织入逻辑,有效实现关注点分离。典型应用如Spring的声明式事务管理,通过动态代理在方法执行前后自动开启和提交事务;MyBatis则利用JDK动态代理将Mapper接口转化为可执行的SQL操作实例。

weixin_35677363的博客 445

cglib动态代理

CGLIB(Code Generation Library),是一个强大的,高性能,高质量的 Code 生成类库,它可以在运行期扩展 Java 类与实现 Java 接口。

NCS123456的博客 1万+

【智能体评测】BrowserUse:一款超越 Anthropic Computer Use 的开源智能体

本文将全面介绍 BrowserUse 的核心功能、配置与使用方法,以及通过多场景测试评估其性能。

surfirst的博客 4087

osgEarth实战:5分钟搞定3DTiles模型加载(附完整配置代码)

本文提供了一份osgEarth加载3DTiles模型的实战指南。通过详解核心Earth文件配置与精简的C++集成代码,帮助开发者快速在三维地球场景中集成倾斜摄影与BIM等海量模型,并分享了性能调优与常见问题排查技巧,有效提升开发效率。

jjj34的博客 473

SpringAOP的CGLIB动态代理的底层原理实现

欢迎加入java学习讨论群:725562382 CGLIB动态代理: CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。 Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成 Hibernate生成持久化类的javassis...

ywl470812087的博客 11万+

Delphi 12.3 精简绿色版下载

Delphi精简绿色版基于原版安装,去掉了InterBase、法语、德语、日语,只保留了Delphi Windows 32和Delphi Windows 64桌面开发,其余部分未做任何修改。Delphi精简绿色版不含任何破解,仅供学习和研究,24小时后请自行删除,如需继续使用Delphi,请购买正版。绿色版基于原版安装,未做任何精简和修改。绿色版不含任何破解,仅供学习和研究,24小时后请自行删除,如需继续使用RAD Studio,请购买正版。

全粘工程师 4258

Spring AOP底层实现原理深度剖析:动态代理与CGLIB的终极对决

在Spring框架的优雅封装之下,AOP(面向切面编程)技术如同一位无形的舞者,轻盈地在核心业务逻辑间穿梭,实现了解耦与增强的双重艺术。而其舞步的核心秘密,正是。

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 988

AMSR-2数据下载实战:从JAXA到LPRM的算法选择与效率优化

本文详细介绍了AMSR-2数据的下载实战,重点对比了JAXA与LPRM算法的差异及适用场景,并提供了高效下载方案和网络优化策略。通过实际案例和代码示例,帮助用户快速获取和处理AMSR-2数据,提升研究效率。

rl6adventurer的博客 686

别再只盯着YOLOv8了!手把手带你用PaddleDetection的PP-YOLOE+搞定你的第一个检测项目

本文介绍了PP-YOLOE+在目标检测领域的优势与应用实践,对比YOLOv8展示其在精度、速度和部署便利性上的突破。通过详细的代码示例和实战教程,帮助开发者快速上手PaddleDetection工具链,实现产业级目标检测项目,提升开发效率。

weixin_42701915的博客 180

【Spring AOP】AOP 底层实现原理 —— 动态代理类的创建(JDK、CGlib)、工厂如何加工原始对象

AOP编程AOP 编程AOP 概念AOP 编程的开发步骤切面的名词解释AOP 的底层实现原理动态代理类的创建JDK 的动态代理(原理 + 编码)CGlib 的动态代理 更多内容请查看笔记目录:【Spring 5.x】学习笔记汇总 AOP 编程 AOP 概念 POP (Producer Oriented Programing) 面向过程(方法、函数)编程 —— C 以过程为基本单位的程序开发,通过过程间的彼此协同,相互调用,完成程序的构建。 OOP (Object Oritened Programin

萌宅鹿的技术小屋 3223

国内9大Coding Plan平台实测:CI/CD延迟与开发者体验横评

代码托管平台不仅是Git仓库,更是现代研发流程的‘生产力基建’核心。其底层能力涵盖Git协议优化、CI/CD调度实时性、制品库并发吞吐及RBAC权限收敛效率等关键维度。尤其在团队规模扩张、日均提交激增、多环境高频部署场景下,Webhook延迟、CI排队耗时、制品上传卡顿等应用层性能指标,远比网络层ping值更能决定开发效能。本文基于真实微服务项目(32模块、8.7万行/仓)与三类极端负载(长尾构建、热区冲突、制品洪峰),对国内9个满足Coding Plan标准的平台开展端到端压测,聚焦CI/CD延迟与开发者

weixin_29281941的博客 365

Spring AOP底层实现原理,使用jdk动态代理以及cglib动态代理

Aop底层使用动态代理实现:有两种情况动态代理 第一种:有接口情况,使用jdk动态代理 第二种:没有接口情况,使用cglib动态代理

qq_45830276的博客 1531

Go游戏服务器开发的一些思考(一):语言层面

Go是比C++更好用的高级语言使用Go作为服务器开发的主语言前,首先需要对Go语言做下定性。在接触Go前,可能给人的印象(至少是我),Go是一门脚本语言。看了 官方文档 ,才知道Go是一门高级语言。与C++相比,它有以下优势: 面向接口的编程没有C++复杂的面向对象语法,如类、继承、多态、虚函数等等。Go中只有结构与接口,从语言层面上,直接指导功能与功能间的解耦。直接且语法简单 提供语言反射机制提供

范安崇的博客 9557

ardupilot开发 --- Remote ID 篇

适配ardupilot的Remote ID模块研发,远程标识模块研发。Remote ID模块可以通过蓝牙或wifi向外广播无人机的状态信息、位置信息、任务信息等,并可以通过蜂窝数据向国家无人驾驶航空器一体化综合监管服务平台上报这些信息。Remote ID功能是21年起国家出台的民用无人机适航飞行的基本要求!

记录老板的每次pua,分享领导每天的毒鸡汤... 9590

Spring原理学习(七)JDK动态代理与CGLIB代理底层实现

编译器也能修改 class 实现增强编译器增强能突破代理仅能通过方法重写增强的限制:可以对构造方法、静态方法等实现增强为什么有这么麻烦的一套东西呢?避免反射,提高性能,代价是一个代理类配两个 FastClass 类,代理类中还得增加仅调用 super 的一堆方法用编号处理方法对应关系比较省内存,另外,最初获得方法顺序是不确定,这个过程没法固定死与JDK动态代理相比,CGLIB代理类数目相对较少,只有两个类。而JDK动态代理在调用到第十七次后会生成代理类去优化为非反射调用,并且是一个方法对应一个代理类。

小鲁蛋的博客 1895

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

JDK动态代理和cglib动态代理(AOP的底层实现原理)

一、代理设计模式 代理类和委托类具有相同的接口。代理类的对象本身并不真正实现服务,而是通过委托类的对象的相关方法来提供特定的服务。 二、静态代理 见《大话设计模式》第7章 缺点: 一个代理类只能应用于一个接口的实现类,如果有多个接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很...

g1607058603的专栏 1053

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

CGLIB动态代理和JDK动态代理-Spring AOP的底层实现原理

简述: AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础。它是一种面向切面编程的思想。关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来讲解下AOP的核心功能的底层实现机制:如何用动态代理来实现切面拦截。         AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生

mrchen的博客 948

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Spring5学习总结(二)AOP底层原理JDK动态代理CGLIB动态代理AOP术语切入点表达式基于xml配置文件实现AOP操作基于注解实现AOP操作五种通知的实现完全注解开发

在软件业,AOP为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗描述:不通过修改源代码的方式实现在主干功能里面添加新功能(例如我想增强已写好的登录功能,不去修改已有的登录代码,而是使用AOP增强)

long3359的博客 244

jdk动态代理与cglib代码实现--SpringAop底层原理

jdk动态代理与cglib代码实现--SpringAop底层原理cglib实现动态代理:jdk实现动态代理:SpringAop中的两种代理方式 动态代理分为两类:基于接口的代理和基于继承的代理 两类实现的代表是:JDK代理 与 CGlib代理 cglib实现动态代理: 1、定义目标对象: public class RealSubject { //目标对象RealSubject,cgli...

龙之竹的博客 553

代理模式的三种实现:静态代理、JDK 动态代理与 CGLIB 代理的底层原理

静态代理:编译时生成,硬编码委托,高效但扩展性差。JDK动态代理:运行时基于接口和反射生成,灵活但仅限接口。CGLIB代理:运行时基于字节码增强和继承生成,支持类代理但需第三方库。选择时需权衡性能、灵活性和依赖:静态代理适合简单场景;JDK动态代理适合接口化系统;CGLIB代理适合无接口或高性能需求。

2501_93878686的博客 668

【Spring】AOP底层实现原理 —— 动态代理类的创建(JDK、CGlib)、工厂加工原始对象

一、AOP概念 AOP (Aspect Oriented Programing) 面向切面编程 = Spring动态代理开发 以切面为基本单位的程序开发,通过切面间的彼此协同,相互调用,完成程序的构建。 切面 = 切入点 + 额外功能 POP (Producer Oriented Programing) 面向过程(方法、函数)编程 —— C 以过程为基本单位的程序开发,通过过程间的彼此协同,相互调用,完成程序的构建。 OOP (Object Oritened Programing) 面向对象编程

See_Star的博客 800

Java面试必备:代理模式源码核心考点解析——JDK动态代理与CGLIB的实现差异及底层原理

代理模式是一种常见的设计模式,通过引入代理对象来控制对原始对象的访问。在Java中,代理主要分为静态代理和动态代理两大类。```java// 接口// 目标类@OverrideSystem.out.println("保存用户: " + username);// 静态代理类}@Overridepublic void saveUser(String username) { System.out.println("前置处理");System.out.println("后置处理");// 使用示例。

2501_93832674的博客 282

Spring框架之AOP动态代理底层实现原理

本文摘要: 本章介绍了AOP的基础实现,重点讲解了JDK动态代理在Spring中的应用。内容包括: AOP概念与实现方式对比:Spring AOP采用动态代理,而AspectJ基于编译期增强 JDK动态代理核心机制:通过Proxy.newProxyInstance创建代理对象,InvocationHandler实现方法增强 示例代码展示:演示了如何创建代理对象并实现前置/后置增强逻辑 Spring的扩展实现:介绍了ReflectiveMethodInvocation类,该类封装方法调用信息,为拦截器链式调用

几许的博客 1551
上一篇: dubbo线程模型及参数优化【持续更新】
下一篇: 各种Buffer傻傻分不清,今天终于有点悟了
开翻挖掘机
博客等级 码龄9年 86粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值