技术博客 技术博客
  • JAVA
  • 仓颉
  • 设计模式
  • 人工智能
  • Spring
  • Mybatis
  • Maven
  • Git
  • Kafka
  • RabbitMQ
  • RocketMQ
  • Redis
  • Zookeeper
  • Nginx
  • 数据库套件
  • MySQL
  • Elasticsearch
  • MongoDB
  • Hadoop
  • ClickHouse
  • Hbase
  • Hive
  • Flink
  • Flume
  • SQLite
  • linux
  • Docker
  • Jenkins
  • Kubernetes
  • 工具
  • 前端
  • AI
GitHub (opens new window)
  • JAVA
  • 仓颉
  • 设计模式
  • 人工智能
  • Spring
  • Mybatis
  • Maven
  • Git
  • Kafka
  • RabbitMQ
  • RocketMQ
  • Redis
  • Zookeeper
  • Nginx
  • 数据库套件
  • MySQL
  • Elasticsearch
  • MongoDB
  • Hadoop
  • ClickHouse
  • Hbase
  • Hive
  • Flink
  • Flume
  • SQLite
  • linux
  • Docker
  • Jenkins
  • Kubernetes
  • 工具
  • 前端
  • AI
GitHub (opens new window)
  • JAVA

    • 基础

      • JAVA 锁 及 线程
      • JAVA NIO API
      • JVM 模块介绍
    • 版本

      • JAVA8 新特性总结
      • JAVA9 新特性总结
      • JAVA 10/11/12/13/14/15/16/17 新特性总结
    • 其他

      • jar 打包成.exe可执行文件
      • java代码混淆之 ProGuard
      • JAVA 性能监控(jvisualvm)及测试(JMeter)
      • Alibaba Arthas
      • jar启动脚本
  • 仓颉

    • 基础

      • 仓颉介绍
  • 设计模式

    • 代理模式
    • 人工智能

      • 线性回归
      • Pytorch
    目录

    代理模式

    Java 中的代理是一种设计模式,它允许在不改变原始对象的情况下,通过引入一个代理对象来控制对原始对象的访问。代理对象充当了客户端与原始对象之间的中介,可以在调用原始对象的方法前后执行一些额外的操作,如权限检查、日志记录等。

    Java 的代理主要有静态代理和动态代理两种实现方式。静态代理需要手动编写代理类,而动态代理则使用 Java 提供的反射机制动态生成代理对象。

    代理的作用包括:

    • 控制对原始对象的访问:代理对象可以限制客户端对原始对象的直接访问,从而增加安全性。
    • 实现远程调用:代理对象可以将方法调用转发到另一台计算机上的对象,从而实现远程调用。
    • 实现懒加载:代理对象可以在需要时才创建原始对象,从而实现懒加载,提高系统性能。
    • 实现事务管理:代理对象可以在调用原始对象的方法前后进行事务操作,从而实现事务管理。

    # 静态代理

    在静态代理中,代理类和原始类实现了相同的接口,客户端通过代理类访问原始类的方法。

    使用 Java 静态代理有以下几个步骤:

    1. 创建一个接口,定义原始对象和代理对象都要实现的方法;
    2. 创建一个原始对象的实现类,并实现接口中的方法;
    3. 创建一个代理类,实现接口并持有原始对象的引用;
    4. 在代理类的方法中,调用原始对象的方法,并在调用前后执行需要的额外操作;
    5. 在客户端代码中,创建一个代理对象,调用代理对象的方法即可。
    // 接口
    public interface Subject {
        void request();
    }
    
    // 原始对象
    public class RealSubject implements Subject {
        public void request() {
            System.out.println("RealSubject: Handling request.");
        }
    }
    
    // 代理类
    public class Proxy implements Subject {
        private RealSubject realSubject;
        
        public Proxy(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
        
        public void request() {
            System.out.println("Proxy: Logging before request.");
            realSubject.request();
            System.out.println("Proxy: Logging after request.");
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            Proxy proxy = new Proxy(realSubject);
            proxy.request();
        }
    }
    // 结果
    Proxy: Logging before request.
    RealSubject: Handling request.
    Proxy: Logging after request.
    
    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

    # 动态代理

    Java 动态代理是一种使用反射机制在运行时动态地生成代理类的技术,可以用来代理一个或多个接口的实现类,并在代理对象调用方法时进行额外的操作。

    Java 动态代理有两种实现方式:基于接口的动态代理(JDK)和基于类的动态代理(CGLIB)。

    • 基于接口的动态代理(JDK):是指代理对象实现(或继承)了被代理对象实现的接口,代理对象通过接口中的方法来实现对被代理对象的代理。这种方式更灵活、安全和低耦合,因为代理对象和被代理对象之间只需要共同实现一个接口即可。
    • 而基于类的动态代理(CGLIB):是指代理对象和被代理对象没有共同实现的接口,但代理对象是被代理对象的子类,因此可以覆盖被代理对象的方法并在其中实现对被代理对象的代理。这种方式相对于基于接口的动态代理来说更灵活,因为代理对象不受被代理对象的接口限制,可以代理任意类的任意方法,但是它也带来了一些问题,例如代理对象无法同时代理多个类,以及可能会破坏被代理对象的封装性和安全性。

    Java 动态代理的作用包括但不限于:

    • 实现 AOP(面向切面编程)的功能,如日志记录、性能统计等;
    • 隐藏某些类或方法的具体实现细节;
    • 实现 RPC(远程过程调用)等功能。
    # JDK 代理

    使用 Java 动态代理需要遵循以下步骤:

    1. 定义一个接口;
    2. 编写一个实现该接口的类;
    3. 创建一个 InvocationHandler 对象,并实现 invoke () 方法,在该方法中对被代理对象的方法进行增强;
    4. 通过 Proxy.newProxyInstance () 方法创建代理对象。该方法需要传入三个参数:ClassLoader 对象、代理对象要实现的接口数组、InvocationHandler 对象;
    5. 调用代理对象的方法,实际上会调用 InvocationHandler 的 invoke () 方法。
    // 接口
    public interface Subject {
        void request();
    }
    
    // 实现类
    public class RealSubject implements Subject {
        public void request() {
            System.out.println("RealSubject: Handling request.");
        }
    }
    
    // InvocationHandler
    public class MyInvocationHandler implements InvocationHandler {
        private Object realObject;
        
        public MyInvocationHandler(Object realObject) {
            this.realObject = realObject;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("MyInvocationHandler: Logging before request.");
            Object result = method.invoke(realObject, args);
            System.out.println("MyInvocationHandler: Logging after request.");
            return result;
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            MyInvocationHandler handler = new MyInvocationHandler(realSubject);
            // 创建代理对象
            Subject proxy = (Subject)Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);
            // 调用代理对象的方法
            proxy.request();
        }
    }
    // 结果
    MyInvocationHandler: Logging before request.
    RealSubject: Handling request.
    MyInvocationHandler: Logging after request.
    
    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
    # CGLIB 代理

    CGLIB 是一个强大的 Java 字节码生成库,能够在运行时动态地生成代理对象。与基于接口的动态代理不同,CGLIB 动态代理可以代理没有实现接口的类。

    使用 CGLIB 动态代理需要依赖 cglib 库,可以通过 Maven 等构建工具引入。下面是一个简单的使用 CGLIB 动态代理的示例:

    1. 定义一个需要代理的类 Person,并定义其相关方法。
    public class Person {
        public void eat() {
            System.out.println("Person: Eating");
        }
    
        public void sleep() {
            System.out.println("Person: Sleeping");
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    1. 创建一个 MethodInterceptor 对象,在 intercept () 方法中实现对被代理对象方法的增强。
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class MyMethodInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("Before " + method.getName());
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("After " + method.getName());
            return result;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    1. 使用 CGLIB 创建代理对象,并调用代理对象的方法。
    import net.sf.cglib.proxy.Enhancer;
    
    public class Main {
        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Person.class);
            enhancer.setCallback(new MyMethodInterceptor());
    
            Person person = (Person)enhancer.create();
            person.eat();
            person.sleep();
        }
    }
    // 结果
    Before eat
    Person: Eating
    After eat
    Before sleep
    Person: Sleeping
    After sleep
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 区别

    基于 CGLIB 和 JDK 动态代理各有优缺点,取决于具体的应用场景和需求。具体优缺点如下:
    优点:

    CGLIB JDK
    可以代理没有实现接口的类 不需要依赖额外的库
    生成的代理类比较小,执行效率高 采用的是接口代理,更加灵活和安全
    支持方法级别的拦截,可以对类中的任意方法进行拦截 在 Java 1.3 及以上版本中可以直接使用,易于部署和维护

    缺点:

    CGLIB JDK
    对于 final 方法或 private 方法无法进行代理 只能代理实现了接口的类
    由于使用继承实现代理,可能会破坏被代理对象的封装性和安全性 生成的代理类相对较大,执行效率不如基于 Java 字节码生成库的代理
    生成的代理类需要依赖额外的库 只能对接口中的方法进行拦截
    上次更新: 6/11/2025, 4:10:30 PM
    仓颉介绍
    线性回归

    ← 仓颉介绍 线性回归→

    Theme by Vdoing | Copyright © 2023-2025
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式