• Java中代理的实现方式


    在这里插入图片描述

    在Java中,有多种方式可以实现代理,包括:

    1. 静态代理:

      • 创建一个代理类,实现与目标类相同的接口或继承与目标类相同的父类。
      • 在代理类中持有一个目标类的引用。
      • 在代理类的方法中,调用目标类的对应方法,并在其前后执行额外的逻辑。
      • 使用代理对象来调用方法,实际上是通过代理类间接调用目标类的方法。
    2. JDK动态代理

      • 定义一个接口,作为代理类和目标类的共同接口。
      • 创建一个实现InvocationHandler接口的代理类。
      • 通过Proxy.newProxyInstance()方法创建代理对象,传入目标类的类加载器、目标类实现的接口和代理类的实例。
      • 在代理类的invoke()方法中,可以在调用目标方法之前和之后执行额外的逻辑。
      • 使用代理对象来调用方法,实际上是通过代理类的invoke()方法间接调用目标类的方法。
    3. CGLIB动态代理

      • 引入CGLIB库的依赖。
      • 创建一个实现MethodInterceptor接口的代理类。
      • 通过Enhancer类创建代理对象,设置目标类作为父类、代理类作为回调对象。
      • 在代理类的intercept()方法中,可以在调用目标方法之前和之后执行额外的逻辑。
      • 使用代理对象来调用方法,实际上是通过代理类的intercept()方法间接调用目标类的方法。

    这些代理方式各有特点,可以根据具体需求选择适合的方式。静态代理相对简单,但需要为每个目标类编写一个代理类;JDK动态代理适用于基于接口的代理;CGLIB动态代理适用于没有实现接口的类的代理。

    1. 静态代理

    // 定义接口
    interface Subject {
        void doSomething();
    }
    
    // 目标类
    class RealSubject implements Subject {
        @Override
        public void doSomething() {
            System.out.println("RealSubject is doing something.");
        }
    }
    
    // 代理类
    class ProxySubject implements Subject {
        private RealSubject realSubject;
    
        public ProxySubject(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
    
        @Override
        public void doSomething() {
            System.out.println("ProxySubject is doing something before RealSubject.");
            realSubject.doSomething();
            System.out.println("ProxySubject is doing something after RealSubject.");
        }
    }
    
    // 使用示例
    public class StaticProxyExample {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            ProxySubject proxySubject = new ProxySubject(realSubject);
            proxySubject.doSomething();
        }
    }
    
    • 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

    在上面的示例中,Subject是一个接口,RealSubject是目标类,实现了Subject接口。ProxySubject是代理类,也实现了Subject接口。在ProxySubject中,我们持有一个RealSubject的引用,并在调用doSomething()方法之前和之后执行额外的逻辑。

    在StaticProxyExample中,我们创建了一个RealSubject对象和一个ProxySubject对象,并调用proxySubject.doSomething()方法。在执行过程中,ProxySubject会在调用RealSubject的doSomething()方法之前和之后输出额外的信息,从而实现对目标类的增强。

    这就是一个简单的静态代理示例,通过代理类包装目标类,实现了对目标类的功能增强。

    2. JDK动态代理

    首先,定义一个接口和一个实现该接口的目标类:

    // 定义接口
    interface Subject {
        void doSomething();
    }
    
    // 实现接口的目标类
    class RealSubject implements Subject {
        @Override
        public void doSomething() {
            System.out.println("RealSubject is doing something.");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    然后,创建一个实现InvocationHandler接口的代理类:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    // 代理类
    class ProxyHandler implements InvocationHandler {
        private Object target;
    
        public ProxyHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Proxy is doing something before RealSubject.");
            Object result = method.invoke(target, args);
            System.out.println("Proxy is doing something after RealSubject.");
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在代理类的invoke()方法中,我们可以在调用目标方法之前和之后执行额外的逻辑。
    最后,创建代理对象并调用方法:

    import java.lang.reflect.Proxy;
    
    public class JDKDynamicProxyExample {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            ProxyHandler proxyHandler = new ProxyHandler(realSubject);
    
            // 创建代理对象
            Subject proxySubject = (Subject) Proxy.newProxyInstance(
                    realSubject.getClass().getClassLoader(),
                    realSubject.getClass().getInterfaces(),
                    proxyHandler);
    
            // 调用代理对象的方法
            proxySubject.doSomething();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在上面的示例中,我们创建了一个RealSubject对象和一个ProxyHandler对象。然后,使用Proxy.newProxyInstance()方法创建代理对象,传入目标类的类加载器、目标类实现的接口和代理类的实例。通过代理对象调用方法时,实际上是调用了代理类的invoke()方法,在其中执行了额外的逻辑,并最终调用目标对象的方法。

    这就是一个简单的使用JDK动态代理的示例,通过代理类和InvocationHandler接口,我们可以在运行时动态地生成代理对象,并在调用目标方法之前和之后执行额外的逻辑。

    3. CGLIB动态代理

    首先,确保在项目中添加CGLIB库的依赖。

    然后,定义一个目标类:

    // 目标类
    class RealSubject {
        public void doSomething() {
            System.out.println("RealSubject is doing something.");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接下来,创建一个实现MethodInterceptor接口的代理类:

    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    // 代理类
    class ProxyInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("Proxy is doing something before RealSubject.");
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("Proxy is doing something after RealSubject.");
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在代理类的intercept()方法中,我们可以在调用目标方法之前和之后执行额外的逻辑。在CGLIB动态代理中,通过MethodProxy对象来调用目标方法。

    最后,创建代理对象并调用方法:

    import net.sf.cglib.proxy.Enhancer;
    
    public class CGLIBDynamicProxyExample {
        public static void main(String[] args) {
            ProxyInterceptor proxyInterceptor = new ProxyInterceptor();
    
            // 创建Enhancer对象
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(RealSubject.class);
            enhancer.setCallback(proxyInterceptor);
    
            // 创建代理对象
            RealSubject proxySubject = (RealSubject) enhancer.create();
    
            // 调用代理对象的方法
            proxySubject.doSomething();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在上面的示例中,我们创建了一个ProxyInterceptor对象,并使用Enhancer类来创建代理对象。通过setSuperclass()方法指定目标类,通过setCallback()方法指定代理类。最后,调用create()方法创建代理对象。

    通过代理对象调用方法时,实际上是调用了代理类的intercept()方法,在其中执行了额外的逻辑,并最终调用目标对象的方法。

    这就是一个简单的使用CGLIB动态代理的示例,通过代理类和MethodInterceptor接口,我们可以在运行时动态地生成代理对象,并在调用目标方法之前和之后执行额外的逻辑。

    扩展

    CGLIB在实现动态代理时使用了ASM库。ASM是一个Java字节码操作和分析框架,可以用于在运行时生成或修改字节码。CGLIB利用ASM库来生成代理类的字节码,以实现对目标类的动态代理。

    在CGLIB中,Enhancer类使用了ASM库来生成代理类的字节码。ASM提供了一套API,可以直接操作字节码,包括创建类、添加字段、添加方法、修改方法等。CGLIB利用ASM的API来生成代理类的字节码,并将其加载到JVM中。

    通过使用ASM库,CGLIB能够在运行时生成代理类的字节码,而无需依赖目标类的接口。这使得CGLIB可以代理那些没有实现接口的类,提供了更大的灵活性。

  • 相关阅读:
    雷达波形之一——LFM线性调频波形
    【知识总结】金九银十offer拿到手软的前端面试题——webpack
    基于Flask开发的前后端交互项目(可用于期末大作业)& MySQL数据库 & 文件上传 & Spider爬虫 & Echarts可视化展示 & JS动态
    运行阶段类型识别RTTI
    python实验10_文件与异常Ⅱ
    LabVIEW和Arduino的巧妙结合(基础篇—1)
    18. `bs对象.节点名.next_sibling` previous_sibling 获取兄弟节点
    STM32 4位数码管和74HC595
    Flink CDC (Mysql为例)
    项目部署(手动版)
  • 原文地址:https://blog.csdn.net/ttyy1112/article/details/132919356