• Java:代理模式详解


    定义:为其他对象提供一种代理以控制对这个对象的访问

    即通过代理对象访问目标对象,这样做的好处是,可以在目标对象实现的基础上,增强额外的功能操作,即拓展目标对象的功能。
    概述

    解决的问题

    在不修改源代码的情况下,对目标对象进行增强。
    优势就是可以在运行时进行增强(动态代理

    核心要点:

    代理是为了扩展类而存在的,可以控制对目标类的服务的访问。
    增加中间层,多了一层控制,多了一层拓展。
    代理模式有不同的表现形式,静态代理、动态代理(JDK的动态代理、Cglib的动态代理)

    类图:

    类图

    代码实现

    需求:通过汽车代理买车的利息

    静态代理

    静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者继承父类
    优点:在不修改目标对象的前提下,能通过代理对象对目标功能拓展
    缺点:由于代理对象需要与目标对象是实现一样的接口,所以会与很多代理类
    一旦接口增加方法,目标对象与代理对象都需要维护

    买车接口BuyCar
    /**
     * 买车的接口
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/8/18 - 17:56
     */
    public interface BuyCar {
    
        public void buyCar();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    真实类-目标对象
    /**
     * @Author: Promsing
     * @Date: 2021/4/3 - 8:25
     * @Description: 实现类
     * @version: 1.0
     */
    public class BuyCarImpl implements BuyCar {
    
        @Override
        public void buyCar() {
            System.out.println("我要买车~~~啦啦啦,真实对象");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    代理类
    /**
     * @Author: Promsing
     * @Date: 2021/4/3 - 8:26
     * @Description: 代理类
     * @version: 1.0
     */
    public class BuyCarProxy implements BuyCar  {
    
        //静态代理- 的实现方式
        private BuyCar buyCar;
    
        //注意final修饰的关键字 不可修改
        //构造函数注入,需要被代理的对象
        public  BuyCarProxy(final BuyCar buyCar) {
            this.buyCar = buyCar;
        }
    
    
        public void buyCar() {
            System.out.println("代理类!买车前的准备~~~");
            buyCar.buyCar();
            System.out.println("代理类!买完车了,出去浪~~~");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    Main方法测试
    /**
     * 静态代理测试类
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/9/7 - 15:19
     */
    public class Main {
    
        public static void main(String[] args) {
    
            //创建代理对象,并指定目标对象
            BuyCar buyCar=new BuyCarProxy(new BuyCarImpl());
            //通过代理对象,对buyCar进行增强
            buyCar.buyCar();
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    动态代理

    JDK动态代理

    代理类所在包:java.lang.reflect.Proxy
    JDK动态代理是通过JDK自带的Proxy类中的newProxyInstance()方法来动态生成代理对象的。
    我们需要实现InvocationHandler接口,在其invoke()方法中编写调用目标对象的代码。

    JDK 动态代理类使用步骤:
    1. 定义一个接口及其实现类;
    2. 实现 InvocationHandler接口 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
    3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 方法创建代理对象;


    动态代理类
    /**
     * @Author: Promsing
     * @Date: 2022/4/3 - 9:09
     * @Description: 动态代理类
     * @version: 1.0
     */
    public class DynamicProxy implements InvocationHandler {
    
        //想相当于切点
        //被代理的真实对象
        private Object object;
    
        public DynamicProxy( Object object) {
            this.object = object;
        }
    
        /**
         *
         * @param proxy  目标对象的引用
         * @param method 当前执行的方法
         * @param args 当前执行方法所需的参数
         * @return 和被代理对象方法有相同的返回值
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println(this.toString());
            System.out.println("不贷款,全款!买车前的准备~~~"); //主要增强
            Object result = method.invoke(object, args);
            System.out.println("买完车了,出去浪~~~"); //主要增强
            return result;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    Main方法测试
    /**
     * 基于接口的动态代理
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/8/18 - 20:06
     */
    public class Main {
    
        
        public static void main(String[] args) {
    
            System.out.println("-+-+-+使用基于接口的代理-+-+-+");
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            System.out.println("$Proxy0.class全名: "+Proxy.getProxyClass(BuyCar.class.getClassLoader(), BuyCar.class).toString());
         
            //使用DynamicProxy类
            //声明一个final修饰的对象--目标类
            final BuyCarImpl car = new BuyCarImpl();
            Object o = Proxy.newProxyInstance(
                    car.getClass().getClassLoader(),
                    car.getClass().getInterfaces(),
                    new DynamicProxy(car));//相对于生成class文件,并加载到内存,并且获取实例
           
            BuyCar proxy2 = (BuyCar) o; //强转,这里必须使用接口
    
            proxy2.buyCar(); //执行代理类的方法
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    运行时代理对象的类型运行时对象

    动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和真实类类的关系是在程序运行时确定。 动态代理根据接口或目标对象,计算出代理类的字节码,然后再加载到JVM中使用。
    其实现原理如下:由于JVM通过字节码的二进制信息加载类的,那么,如果我们在运行期系统中,遵循Java编译系统组织.class文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据加载转换成对应的类, 这样,就完成了在代码中,动态创建一个类的能力了。

    Cglib动态代理

    由于JDK动态代理是面向接口的,也就是说如果目标类没有相应的接口,JDK动态代理就无法为其创建代理。这时可以选择用CGLIB动态代理来实现。
    Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象拓展。
    Cglib包的底层通过字节码处理框架ASM来转换字节码并生成新的类
    需要引入Jar包–cglib 本案例使用cglib3.3.0

    CGLIB 动态代理类使用步骤
    1. 实现 MethodInterceptor接口 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
    2. 通过 Enhancer 类的 create()创建代理类
    3. 客户端使用代理对象
    动态代理类
    /**
     * 实现方法拦截的接口
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/8/19 - 0:00
     */
    public class DynamicSubClass implements MethodInterceptor {
        
        
        //真实对象
        private Object target;
    
        public DynamicSubClass(Object target) {
            this.target = target;
        }
    
     
        //返回一个代理对象
        public Object getProxyInstance(){
            //创建工具类
            Enhancer enhancer = new Enhancer();
    
            //设置父类
            enhancer.setSuperclass(target.getClass());
    
            //回调函数
            enhancer.setCallback(this);
    
            //创建代理对象
            return enhancer.create();
        }
        
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("不贷款,全款!买车前的准备~~~"); //增强的逻辑
            Object result = methodProxy.invokeSuper(o, objects);
            System.out.println("买完车了,出去浪~~~");
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    Main方法测试
    public class Main2 {
    
        public static void main(String[] args) {
    
            //使用基于子类的动态代理
            //需要引入Jar包--cglib 本案例使用cglib3.3.0
            System.out.println("-+-+-+使用基于子类的代理-+-+-+");
    
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:\\09  个人学习\\com\\sun\\proxy");
    
            final BuyCarImpl car=new BuyCarImpl(); //目标类
    
            //生成代理对象
            Object o = new DynamicSubClass(car).getProxyInstance();
            BuyCar buyCar=(BuyCar) o;
    
            buyCar.buyCar();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行时代理对象的类型
    运行时对象

    拓展

    JDK生成的字节码文件

    看源码得知,代理文件继承了Proxy,实现了BuyCar接口,由于Java是单继承,所以JDK的动态代理只能基于接口实现

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.sun.proxy;
    
    import com.promsing.porxy.v2.BuyCar;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements BuyCar {
        private static Method m1;//equals
        private static Method m2;//tostring
        private static Method m3;//buyCar
        private static Method m0;//hascode
    
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void buyCar() throws  {
            try {//h,就是切面类(代理类)
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.promsing.porxy.v2.BuyCar").getMethod("buyCar");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    Cglib生成的字节码文件

    看源码得知,代理文件继承了BuyCarImpl,所以cglib是基于子类的动态代理
    在这里插入图片描述

    public class BuyCarImpl$$EnhancerByCGLIB$$1caed7b0 extends BuyCarImpl implements Factory {
     
    
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.promsing.structure.proxy.v2.BuyCarImpl$$EnhancerByCGLIB$$1caed7b0");
            Class var1;
            Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
            CGLIB$finalize$1$Method = var10000[0];
            CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
            CGLIB$equals$2$Method = var10000[1];
            CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
            CGLIB$toString$3$Method = var10000[2];
            CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
            CGLIB$hashCode$4$Method = var10000[3];
            CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
            CGLIB$clone$5$Method = var10000[4];
            CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
            CGLIB$buyCar$0$Method = ReflectUtils.findMethods(new String[]{"buyCar", "()V"}, (var1 = Class.forName("com.promsing.structure.proxy.v2.BuyCarImpl")).getDeclaredMethods())[0];
            CGLIB$buyCar$0$Proxy = MethodProxy.create(var1, var0, "()V", "buyCar", "CGLIB$buyCar$0");
        }
    
        final void CGLIB$buyCar$0() {
            super.buyCar();
        }
        
        //buyCar的方法
        public final void buyCar() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                var10000.intercept(this, CGLIB$buyCar$0$Method, CGLIB$emptyArgs, CGLIB$buyCar$0$Proxy);
            } else {
                super.buyCar();
            }
        }
    
    ·
        final boolean CGLIB$equals$2(Object var1) {
            return super.equals(var1);
        }
        
        //equals
        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$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
                return var2 == null ? false : (Boolean)var2;
            } else {
                return super.equals(var1);
            }
        }
    
        final String CGLIB$toString$3() {
            return super.toString();
        }
        //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$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
        }
    
        final int CGLIB$hashCode$4() {
            return super.hashCode();
        }
        //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$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
                return var1 == null ? 0 : ((Number)var1).intValue();
            } else {
                return super.hashCode();
            }
        }
    
        final Object CGLIB$clone$5() 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$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
            String var10000 = var0.toString();
            switch(var10000.hashCode()) {
            case -1574182249:
                if (var10000.equals("finalize()V")) {
                    return CGLIB$finalize$1$Proxy;
                }
                break;
            case -1261565625:
                if (var10000.equals("buyCar()V")) {
                    return CGLIB$buyCar$0$Proxy;
                }
                break;
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$5$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$2$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$3$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$4$Proxy;
                }
            }
    
            return null;
        }
    
        public BuyCarImpl$$EnhancerByCGLIB$$1caed7b0() {
            CGLIB$BIND_CALLBACKS(this);
        }
    
    
    
        public Object newInstance(Callback var1) {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
            BuyCarImpl$$EnhancerByCGLIB$$1caed7b0 var10000 = new BuyCarImpl$$EnhancerByCGLIB$$1caed7b0();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
            CGLIB$SET_THREAD_CALLBACKS(var3);
            BuyCarImpl$$EnhancerByCGLIB$$1caed7b0 var10000 = new BuyCarImpl$$EnhancerByCGLIB$$1caed7b0;
            switch(var1.length) {
            case 0:
                var10000.<init>();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175

    jdk的动态代理与cglib动态代理的底层实现

    1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
    2.JDK和Cglib都是在运行期生成字节码,JDK是直接写成代理对象Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
    3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。
    4.cglib封装了ASM这个开源框架,对字节码操作,完成对代理类的创建.主要通过集成目标对象,然后完成重写,再操作字节码

    ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

    FastClass 的原理简单来说就是:为不需要反射 invoke 调用的原类型生成一个 FastClass 类,然后给原类型的方法分配一个 index,在生成的 FastClass 中的 invoke 方法中,先直接把 Object 强制转换为原类型,然后根据这个 index,就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比 JDK 动态代理通过反射调用高。

    在这里插入图片描述

    拓展:https://blog.csdn.net/z69183787/article/details/106878203/
    若动态代理要对目标类的增强逻辑进行拓展,结合策略模式,只需要新增策略类,无需修改代理类代码

    Spring 中何时使用 JDK 或 CGLIB

    如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP
    如果目标对象实现了接口,也可以强制使用 CGLIB 实现 AOP
    如果目标对象没有实现接口,必须采用 CGLIB,Spring 会自动在 JDK 动态代理和 CGLIB 之间转换
    答案:DefaultAopProxyFactory类中有源码

    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    
    	@Override
    	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    		//JDK动态代理和CGlib的选择,判断是否配置,判断是否是接口
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    			Class<?> targetClass = config.getTargetClass();
    			if (targetClass == null) {
    				throw new AopConfigException("TargetSource cannot determine target class: " +
    						"Either an interface or a target is required for proxy creation.");
    			}
    			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}
    
    	/**
    	 * Determine whether the supplied {@link AdvisedSupport} has only the
    	 * {@link org.springframework.aop.SpringProxy} interface specified
    	 * (or no proxy interfaces specified at all).
    	 */
    	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
    		Class<?>[] ifcs = config.getProxiedInterfaces();
    		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏

  • 相关阅读:
    VTK实现裁剪删除模型功能
    Elasticsearch环境配置
    DSP2335的按键输入key工程笔记
    【基于Kmeans、Kmeans++和二分K均值算法的图像分割】数据挖掘实验三
    数值常量如何转化为内存地址?
    OrcaTerm AI
    每日刷题打卡Day12
    java实现图片转pdf
    不会分布式?阿里p9架构师推荐分布式系统开发实战文档
    Cys(Npys)-(Arg)₉,H2N-C(Npys)-RRRRRRRRR-OH
  • 原文地址:https://blog.csdn.net/promsing/article/details/126774641