java 代理模式实现

代理

代理模式

代理模式是一种结构型设计模式,概念为通过一个代理对象来控制对原始对象的访问,代理对象通常表现出的行为与原始对象一致(实现同一接口)以便于可以在使用原始对象的地方代替原始对象。使用代理模式一般用来保护以及增强原始对象。

静态代理与动态代理

编译期间就确定好了代理类与被代理类为静态代理,其中代理类与被代理类会实现同一个接口,代理类持有被代理类,代理类可以调用被代理类方法并添加逻辑。

动态代理的代理类是运行期间动态生成的,其他地方与静态代理相同。很显然在被代理类很多时使用动态代理可以节省代码且方便修改逻辑。

静态代理一般来说效率稍高,但是代码冗余大,不便于修改。

动态代理一般使用 jdk 动态代理和 cglib 动态代理。

jdk 动态代理

jdk 动态代理是基于实现接口的方式,代理类是动态生成的和被代理类实现同一接口且持有被代理类实例的类。

很显然 jdk 动态代理是代理不了接口中没有的方法的。

jdk 动态代理基于反射,代理类与被代理类是委托关系,使用 Proxy 生成字节码文件。

涉及到以下几个类和接口

InvocationHandler 接口

动态代理类需要实现这个接口且持有被代理类实例,通过代理对象调用一个方法时,这个方法的调用会被转发由这个接口的 invoke 方法来进行调用

java 复制代码
// InvocationHandler 唯一的接口
Object invoke(Object proxy, Method method, Object[] args)throws Throwable 

参数说明:

  • proxy - 被代理类实例
  • method - 被代理类的某个方法的 Method 对象
  • args - 调用被代理类某个方法时需要的参数列表
Proxy 类

Proxy 这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,用的最多的就是 newProxyInstance 方法:

java 复制代码
//得到一个动态的代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

参数说明:

  • loader - 一个 ClassLoader 对象,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载
  • interfaces - 一个接口对象的数组,表示代理对象需要实现的接口
  • h - 一个 InvocationHandler 对象,表示代理对象调用方法时需要关联的 InvocationHandler 对象
动态生成的类

只会生成一个类,这是其反编译后的代码示例

java 复制代码
//继承了java.lang.reflect.Proxy,实现了被代理类的接口
public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) {
        //使用父类的构造方法
        super(var1);
    }
    
    ...

    public final void deal() {
        try {
            //调用InvocationHandler的invoke方法
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    ...

    static {
        try {
            //Object的equals方法
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            //Object的toString方法
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            //被代理类的接口中的方法,如果接口中有多个方法会往后延
            m3 = Class.forName("动态代理.jdk动态代理.Subject").getMethod("deal");
            //Object的hashCode方法
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

其调用关系为

调用方 -> 动态生成的代理类的对应方法 -> 拦截器的 invoke 方法 -> 被代理类的对应方法

cglib 动态代理

cglib 动态代理是基于继承的方式,代理类是动态生成的继承了被代理类的类,使用重写方法的方式实现增强。

由于 cglib 动态代理是基于继承的,因此代理不了私有方法、final 方法、静态方法和构造方法,以及被声明为 final 的类。

cglib 动态代理基于FastClass方法索引,第一次调用需要生成 Class 对象较慢,代理类与被代理类是继承关系,使用ASM框架生成字节码文件。

MethodInterceptor

拦截器需要实现的接口,通过代理对象调用一个方法时,这个方法的调用会被转发由这个接口的 intercept 方法来进行调用

java 复制代码
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable

参数说明:

  • o - 代理类
  • method - 被代理的方法
  • args - 调用时的参数
  • methodProxy - 方法的代理类
FastClass

索引类,其中有两个主要的方法

  • getIndex - 获取目标的编号;索引类记录了目标方法与编号之间的对应关系,传递方法签名信息并返回对应编号
  • invoke - 根据方法编号,调用目标方法;三个参数分别代表
    • index - 方法编号
    • target - 目标对象
    • args - 方法执行所需参数
java 复制代码
//代理类的FastClass
public class RealSubject$$FastClassByCGLIB$$b86fb30b extends FastClass {
    public RealSubject$$FastClassByCGLIB$$b86fb30b(Class var1) {
        super(var1);
    }

    //根据方法的签名获取对应的索引
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
            case 1540437897:
                if (var10000.equals("deal()V")) {
                    return 0;
                }
                break;
            ...
        }

        return -1;
    }

    ...

    //根据方法索引调用被索引类的对应方法
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        RealSubject var10000 = (RealSubject)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
                case 0:
                    var10000.deal();
                    return null;
                ...
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

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

在代理类初始化时被创建

java 复制代码
public class RealSubject$$EnhancerByCGLIB$$679604bd extends RealSubject implements Factory {
    
    ...
    
    private static Method CGLIB$deal$0$Method;
    private static MethodProxy CGLIB$deal$0$Proxy;
    
    ...
    
    static void CGLIB$STATICHOOK1() throws ClassNotFoundException {
        ...
        CGLIB$deal$0$Method = ReflectUtils.findMethods(new String[]{"deal", "()V"}, (var1 = Class.forName("动态代理.cglib动态代理.RealSubject")).getDeclaredMethods())[0];
        //关联了代理的方法与被代理的方法
        CGLIB$deal$0$Proxy = MethodProxy.create(var1, var0, "()V", "deal", "CGLIB$deal$0");
    }
    
    static {
        try {
            CGLIB$STATICHOOK1();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

在 invoke 或者 invokeSuper 方法调用时被初始化

java 复制代码
public class MethodProxy {
    public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            //初始化
            this.init();
            MethodProxy.FastClassInfo fci = this.fastClassInfo;
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        } catch (IllegalArgumentException var5) {
            if (this.fastClassInfo.i1 < 0) {
                throw new IllegalArgumentException("Protected method: " + this.sig1);
            } else {
                throw var5;
            }
        }
    }
    
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            //初始化
            this.init();
            MethodProxy.FastClassInfo fci = this.fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        }
    }
    
    private void init() {
        //如果没有初始化的话
        if (this.fastClassInfo == null) {
            synchronized(this.initLock) {
                if (this.fastClassInfo == null) {
                    MethodProxy.CreateInfo ci = this.createInfo;
                    MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                    //获取代理类和被代理类的索引类,其中f1是被代理类的索引类,f2是代理类的索引类
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    //类似的,i1是被代理方法的索引值,i2是代理类的索引值
                    fci.i1 = fci.f1.getIndex(this.sig1);
                    fci.i2 = fci.f2.getIndex(this.sig2);
                    this.fastClassInfo = fci;
                    this.createInfo = null;
                }
            }
        }
    }
}
动态生成的类

会生成三个类,分别是代理类、代理类的索引类、被代理类的索引类

java 复制代码
//动态生成的代理类
public class RealSubject$$EnhancerByCGLIB$$679604bd extends RealSubject implements Factory {
    ...
    //直接调用被代理方法的方法
    final void CGLIB$deal$0() {
        super.deal();
    } 
        
    //重写的被代理类的方法
    public final void deal() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            try {
                //调用拦截器的intercept方法
                var10000.intercept(this, CGLIB$deal$0$Method, CGLIB$emptyArgs, CGLIB$deal$0$Proxy);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        } else {
            super.deal();
        }
    }
    ...
}

//代理类的FastClass
public class RealSubject$$EnhancerByCGLIB$$679604bd$$FastClassByCGLIB$$d3b917bf extends FastClass {
    ...
}

//代理类的FastClass
public class RealSubject$$FastClassByCGLIB$$b86fb30b extends FastClass {
}

其调用关系为

调用方 -> 动态生成的代理类的对应方法的重载 -> 自定义的拦截器的 intercept 方法 -> 代理类索引类的 invoke 方法 -> 动态生成的代理类的直接调用父类对应方法的实现 -> 被代理类
调用方 代理类 拦截器 MethodProxy 代理类索引类 被代理类 业务方法() 1. intercept() 2. 前置拦截 3. invokeSuper() 4. getIndex() 5. 返回方法索引 6. invoke() 7. CGLIB业务方法?() 8. 业务方法 9. 返回 10. 返回 11. 返回 12. 返回 13. 后置拦截 14. 返回 15. 返回 调用方 代理类 拦截器 MethodProxy 代理类索引类 被代理类

相关推荐
fly-phantomWing3 分钟前
在命令提示符页面中用pip命令行安装Python第三方库的详细步骤
开发语言·python·pip
VBA633732 分钟前
VBA数据库解决方案第二十三讲:向一个已有数据表中添加数据记录
开发语言
奔跑吧邓邓子40 分钟前
【C++实战㊺】解锁C++代理模式:从理论到实战的深度剖析
c++·实战·代理模式
@@神农1 小时前
maven的概述以及在mac安装配置
java·macos·maven
杜子不疼.1 小时前
【C++】玩转模板:进阶之路
java·开发语言·c++
夜晚中的人海1 小时前
【C++】异常介绍
android·java·c++
Le1Yu2 小时前
2025-9-28学习笔记
java·笔记·学习
C++chaofan2 小时前
项目中为AI添加对话记忆
java·数据结构·人工智能·redis·缓存·个人开发·caffeine
老华带你飞2 小时前
机电公司管理小程序|基于微信小程序的机电公司管理小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·微信小程序·小程序·机电公司管理小程序
拾忆,想起2 小时前
AMQP协议深度解析:消息队列背后的通信魔法
java·开发语言·spring boot·后端·spring cloud