楼主: 铁臂小彤彤
45 0

[作业] Java 代理模式:原理、实现与应用场景 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-5-10
最后登录
2018-5-10

楼主
铁臂小彤彤 发表于 2025-11-27 14:49:21 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

代理模式是 Java 设计模式中的一种结构型模式,其主要思想是通过引入一个代理对象来间接访问目标对象。这种方式可以在不改动原始类代码的基础上,对目标对象的功能进行增强,例如实现权限控制、日志记录或性能监控等功能,同时还能隐藏目标对象的具体实现细节。

一、代理模式的三大核心角色

  • 抽象主题(Subject):作为代理对象和目标对象共同遵循的接口,它定义了两者对外暴露的方法,使客户端可以通过统一的方式进行调用。
  • 目标对象(RealSubject):实现了抽象主题接口,负责具体的业务逻辑执行,是实际的服务提供者。
  • 代理对象(Proxy):同样实现抽象主题接口,并持有目标对象的引用,在调用真实方法前后可插入额外处理逻辑。

二、代理模式的主要分类与实现方式

根据代理类生成的时机和机制不同,Java 中的代理模式可分为静态代理动态代理两种形式。其中动态代理又包括 JDK 动态代理与 CGLIB 动态代理。

1. 静态代理

静态代理在编译阶段就已经确定了代理关系,代理类由程序员手动编写并编译成字节码文件。

实现流程如下:

  1. 定义公共接口(抽象主题);
  2. 创建目标类实现该接口;
  3. 创建代理类也实现同一接口,并在内部维护对目标对象的引用,从而在方法调用时添加增强逻辑。
// 1. 抽象主题接口
public interface UserService {
    void addUser(String username);
}

// 2. 目标对象:实现抽象主题
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("添加用户:" + username);
    }
}

// 3. 代理对象:增强目标对象功能
public class UserServiceProxy implements UserService {
    // 持有目标对象引用
    private UserService target;

    public UserServiceProxy(UserService target) {
        this.target = target;
    }

    @Override
    public void addUser(String username) {
        // 前置增强:日志记录
        System.out.println("【日志】开始添加用户,用户名:" + username);
        // 调用目标对象方法
        target.addUser(username);
        // 后置增强:结果校验
        System.out.println("【日志】用户添加完成");
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        UserService proxy = new UserServiceProxy(target);
        proxy.addUser("张三");
    }
}

优点与局限性:

  • 优点:结构清晰,易于理解,不会侵入原有业务逻辑;
  • 缺点:每个目标类都需要对应一个代理类,当接口方法增加时,代理类需同步修改,维护成本较高;难以应对大量类的代理需求。

2. 动态代理

动态代理在程序运行期间动态生成代理类,无需预先编写代理代码,具备更高的灵活性,适用于需要为多个类统一添加横切逻辑的场景。

(1)JDK 动态代理

JDK 动态代理依赖于 Java 的反射机制,要求目标类必须实现至少一个接口,因为代理类会实现相同的接口以保证行为一致性。其核心组件包括:

  • InvocationHandler 接口 —— 用于定义拦截逻辑;
  • Proxy 类 —— 提供静态方法生成代理实例。
java.lang.reflect.Proxy
java.lang.reflect.InvocationHandler

实现步骤:

  1. 自定义类实现 InvocationHandler 接口,并重写 invoke 方法,在其中编写前置/后置操作及目标方法的调用逻辑;
  2. invoke
  3. 使用 Proxy.newProxyInstance() 方法创建代理对象。
  4. Proxy.newProxyInstance()
// 1. 抽象主题接口(复用上述UserService)
// 2. 目标对象(复用上述UserServiceImpl)

// 3. 自定义InvocationHandler
public class MyInvocationHandler implements InvocationHandler {
    // 目标对象(通用类型,适配不同接口)
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强:权限校验
        System.out.println("【权限校验】检查是否有权限调用" + method.getName() + "方法");
        // 调用目标对象方法
        Object result = method.invoke(target, args);
        // 后置增强:性能监控
        System.out.println("【性能监控】" + method.getName() + "方法执行耗时:10ms");
        return result;
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        // 生成动态代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),  // 目标类类加载器
            target.getClass().getInterfaces(),   // 目标类实现的接口
            new MyInvocationHandler(target)      // 自定义InvocationHandler
        );
        proxy.addUser("李四");
    }
}

特点总结:

  • 基于接口编程,实现了解耦;
  • 代理类在运行期自动生成,无需手动编码;
  • 限制在于目标类必须实现接口,否则无法应用此方式。
(2)CGLIB 动态代理

CGLIB 是一个基于 ASM 框架的字节码生成库,能够在运行时动态生成目标类的子类来实现代理功能,因此不要求目标类实现接口。

实现步骤:

  1. 引入 CGLIB 依赖(常见框架如 Spring 已内置支持);
  2. 定义类实现 MethodInterceptor 接口;
  3. intercept
  4. 利用 Enhancer 类创建代理实例。
// 1. 目标类(无需实现接口)
public class OrderService {
    public void createOrder(String orderNo) {
        System.out.println("创建订单:" + orderNo);
    }
}

// 2. 自定义MethodInterceptor
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 前置增强:日志记录
        System.out.println("【CGLIB代理】调用方法:" + method.getName());
        // 调用目标对象方法
        Object result = proxy.invokeSuper(obj, args);
        // 后置增强:结果处理
        System.out.println("【CGLIB代理】方法执行完成");
        return result;
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        // 创建Enhancer对象,用于生成代理类
        Enhancer enhancer = new Enhancer();
        // 设置父类(目标类)
        enhancer.setSuperclass(OrderService.class);
        // 设置回调(增强逻辑)
        enhancer.setCallback(new MyMethodInterceptor());
        // 生成代理对象
        OrderService proxy = (OrderService) enhancer.create();
        proxy.createOrder("ORDER_123456");
    }
}

特性说明:

  • 无需接口约束,适用范围更广;
  • 通过继承方式实现代理,故目标类不能声明为 final;
  • 性能优于 JDK 动态代理(尤其在早期版本),但在 JDK 8 及以后差距逐渐缩小。

三、典型应用场景

  • Spring AOP:Spring 框架底层结合使用 JDK 动态代理(对接口类)与 CGLIB 动态代理(对无接口类),实现事务管理、日志记录、缓存等横切关注点的统一织入。
  • 远程代理:如 Dubbo 等 RPC 框架中,客户端通过本地代理对象调用远程服务方法,屏蔽底层网络通信复杂性。
  • 虚拟代理:用于延迟加载重型资源,例如 Hibernate 的懒加载机制,通过代理控制真实数据的初始化时机。
  • 保护代理:在权限控制系统中,通过代理拦截非法访问请求,确保只有授权用户才能调用特定方法。

四、三种代理方式对比分析

特性 静态代理 JDK 动态代理 CGLIB 动态代理
实现方式 手动编写代理类 反射 + 接口 字节码生成 + 继承
目标类要求 无需强制实现接口 必须实现接口 不能为 final,无需接口
灵活性 低(需逐一手动维护) 高(运行期动态生成) 高(运行期动态生成)
性能表现 高(编译期已确定) 中(存在反射开销) 高(直接生成字节码)

总结

代理模式通过引入中间层——代理对象,实现了对目标对象访问的间接控制。这种设计既保障了原始类的封装性,又提供了良好的扩展能力。静态代理适合逻辑简单、变动较少的场景;而动态代理因其高度灵活,在现代框架开发中占据重要地位,尤其是 Spring AOP 等基础设施中的广泛应用。实际项目中,应结合目标类是否实现接口、性能要求以及可维护性等因素,合理选择合适的代理技术方案。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Java jav Interfaces Intercept implement

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-21 23:43