结构型模式 - 代理模式 (Proxy Pattern)

news/2025/2/26 21:45:24

结构型模式 - 代理模式 (Proxy Pattern)

代理模式是一种结构型设计模式,它允许通过代理对象来控制对另一个对象(目标对象)的访问。代理对象充当目标对象的接口,客户端通过代理对象间接访问目标对象。


分为两大类

  • 静态代理(编译时就知道
  • 动态代理(Java程序运行时才知道

Java 静态代理

// 定义用户服务接口
public interface UserService {
    // 添加用户方法
    void addUser(String username);
}

// 实现用户服务接口的具体类
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("添加用户: " + username);
    }
}

// 用户服务的代理类
public class UserServiceProxy implements UserService {
    // 持有目标对象
    private UserService target;

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

    @Override
    public void addUser(String username) {
        // 在调用目标方法之前添加额外逻辑,这里是打印日志
        System.out.println("开始添加用户操作,记录日志...");
        // 调用目标对象的方法
        target.addUser(username);
        // 在调用目标方法之后添加额外逻辑,这里是打印日志
        System.out.println("添加用户操作完成,记录日志...");
    }
}

// 测试静态代理的类
public class StaticProxyTest {
    public static void main(String[] args) {
        // 创建目标对象
        UserService target = new UserServiceImpl();
        // 创建代理对象,并将目标对象传入
        UserService proxy = new UserServiceProxy(target);

        // 通过代理对象调用添加用户方法
        proxy.addUser("张三");
        System.out.println();
    }
}

Java 动态代理又细分为两类

  • jdk 代理
  • cglib 代理
// jdk 方式

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 业务接口
public interface UserService {
    void addUser(String username);
}

// 业务接口实现类
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("添加用户: " + username);
    }
}

// 代理处理器
class UserServiceProxyHandler implements InvocationHandler {
    private final Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用目标方法之前添加额外逻辑
        System.out.println("开始执行添加用户操作...");
        // 调用目标方法
        Object result = method.invoke(target, args);
        // 在调用目标方法之后添加额外逻辑
        System.out.println("添加用户操作执行完毕。");
        return result;
    }
}

// 测试类
public class JdkProxyExample {
    public static void main(String[] args) {
        // 创建目标对象
        UserService target = new UserServiceImpl();
        // 创建代理处理器
        UserServiceProxyHandler handler = new UserServiceProxyHandler(target);
        // 生成代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler
        );
        // 调用代理对象的方法
        proxy.addUser("张三");
    }
}
// cglib 代理

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 业务类
public class UserManager {
    public void addUser(String username) {
        System.out.println("添加用户: " + username);
    }
}

// 代理拦截器
public class UserManagerInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 在调用目标方法之前添加额外逻辑
        System.out.println("开始执行添加用户操作...");
        // 调用目标方法
        Object result = proxy.invokeSuper(obj, args);
        // 在调用目标方法之后添加额外逻辑
        System.out.println("添加用户操作执行完毕。");
        return result;
    }
}

// 测试类
public class CglibProxyExample {
    public static void main(String[] args) {
        // 创建 Enhancer 对象
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(UserManager.class);
        // 设置回调函数
        enhancer.setCallback(new UserManagerInterceptor());
        // 生成代理对象
        UserManager proxy = (UserManager) enhancer.create();
        // 调用代理对象的方法
        proxy.addUser("李四");
    }
}

对比分析

根本差异体现

代理机制

  • JDK 代理:依赖接口。在 JDK 代理示例中,UserService 是一个接口,UserServiceImpl 实现了该接口,代理对象是基于接口生成的。
  • CGLIB 代理:基于继承。在 CGLIB 代理示例中,UserManage 是一个普通类,代理对象是 UserManage 的子类。

方法调用

  • JDK 代理:在 InvocationHandler 的 invoke 方法中,使用 method.invoke(target, args) 调用目标对象的方法,这里的 target 是实际的目标对象。
  • CGLIB 代理:在 MethodInterceptor 的 intercept 方法中,使用 proxy.invokeSuper(obj, args) 调用目标类的方法,obj 是代理对象本身。

http://www.niftyadmin.cn/n/5869190.html

相关文章

互联网+房产中介+装修设计+物料市场+智能家居一体化平台需求书

一、项目概述 1.1 项目背景 随着互联网技术的飞速发展以及人们生活品质的显著提升,传统房产交易、装修设计、家居购物等领域暴露出诸多问题。信息不对称使得用户难以获取全面准确的信息,在房产交易中可能高价买入或低价卖出,装修时可能遭遇…

windows笔记本如何设置显示器和笔记本屏幕显示的一样

windows笔记本如何设置显示器和笔记本屏幕显示的一样 DeepSeek R1 思考 27 秒 思考过程 好的,用户问的是Windows笔记本如何设置显示器和笔记本屏幕显示一样。我需要先理解用户的具体需求。这里的“显示器和笔记本屏幕显示一样”可能有两种情况:一种是希…

数据安全_笔记系列06:数据生命周期管理(存储、传输、使用、销毁)深度解析

数据安全_笔记系列06:数据生命周期管理(存储、传输、使用、销毁)深度解析 数据生命周期管理(存储、传输、使用、销毁)详解 数据生命周期管理(Data Lifecycle Management, DLM)是围绕数据从创建…

汽车无钥匙进入一键启动操作正确步骤

汽车智能无钥匙进入和一键启动的技术在近年来比较成熟,不同车型的操作步骤可能略有不同,但基本的流程应该是通用的,不会因为时间变化而有大的改变。 移动管家汽车一键启动无钥匙进入系统通常是通过携带钥匙靠近车辆,然后触摸门把…

C语言 第一章 认识C语言

目录 C语言的发展史 为什么要学习C语言 常用的IDE工具 Dev-C Microsoft Visual Studio CLion 第一个编程程序 C语言的程序运行机制 C语言的程序结构 C语言的发展史 1960年,ALGOL 60语言诞生,它的块结构、数据类型等概念为C语言奠定了基础。196…

DeepSeek赋能大模型内容安全,网易易盾AIGC内容风控解决方案三大升级

在近两年由AI引发的生产力革命的背后,一场关乎数字世界秩序的攻防战正在上演:AI生成的深度伪造视频导致企业品牌声誉损失日均超千万,批量生成的侵权内容使版权纠纷量与日俱增,黑灰产利用AI技术持续发起欺诈攻击。 与此同时&#…

C++ openssl AES/CBC/PKCS7Padding 256位加密 解密示例 MD5示例

C openssl AES/CBC/PKCS7Padding 256位加密 解密示例 加密 为了确保 AES 加密使用 AES/CBC/PKCS7Padding,我们需要确保在加密过程中正确处理填充。OpenSSL 的 AES_cbc_encrypt 函数并不自动处理填充,因此我们需要手动实现 PKCS7 填充。 以下是更新后…

一文掌握Splash的详细使用

文章目录 1. 安装与启动 Splash1.1 使用 Docker 安装1.2 直接安装 2. 基本用法2.1 访问 Splash 界面2.2 使用 Splash 渲染页面2.3 使用 Lua 脚本 3. 高级用法3.1 处理 JavaScript3.2 截图与 PDF3.3 处理 AJAX 请求3.4 设置请求头3.5 处理 Cookies 4. 与 Scrapy 集成4.1 安装 Sc…