当前位置: 首页 > article >正文

什么是代理模式?

Java中的代理模式是一种结构型设计模式,它允许通过代理对象来控制对另一个对象的访问。这种模式在Java中有着广泛的应用,特别是在需要增强对象功能、控制访问权限或实现某些特定行为时。下面会对Java代理模式进行详细解释。

一、基本概念


代理模式涉及三个主要角色:

抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。


二、静态代理


定义:静态代理是在编译时就已经确定代理类和被代理类的关系,代理类需要手动实现和被代理类相同的接口,并调用被代理类的方法。


特点:
代理类和被代理类都实现了相同的接口。
代理类的对象在程序运行之前就已经确定。
代理对象中会包含目标对象的引用。

优点:
可以在不修改目标对象的情况下扩展目标对象的功能。
由于代理类是预先编写好的,所以运行时效率较高。

缺点:
需要为每一个目标对象创建一个对应的代理类,如果目标对象很多,则代理类也会很多,增加了代码的复杂性。
如果目标接口增加了新的方法,则代理类和目标类都需要进行相应的修改,增加了维护成本。


三、动态代理


定义:动态代理是在运行时动态生成代理类,不需要手动实现接口,可以在运行时为任意一个类创建代理对象。


分类:
基于接口的动态代理(JDK动态代理):JDK动态代理是Java自带的动态代理机制,它是在运行时通过反射机制生成代理类,代理类实现了指定接口,从而实现对该接口的代理操作。被代理的类必须实现一个接口。
基于类的动态代理(CGLIB动态代理):CGLIB动态代理是基于类的代理,它不需要被代理的类实现一个接口,而是直接继承被代理类,通过子类代理的方式实现对被代理类的代理操作。CGLIB是一个优秀的字节码生成库,通过在运行时动态生成字节码,实现对被代理类的代理操作。


优点:
灵活性高,可以动态地为不同的目标对象创建代理,而无需预先知道目标对象的具体类型。
只需要编写一次代理逻辑,就可以适用于所有的代理对象,降低了代码的重复性。


缺点:
JDK动态代理要求目标对象必须实现一个接口,否则无法使用。
由于涉及到反射,运行时效率相对较低。
CGLIB动态代理只能代理非final类和非final方法,且由于是通过继承实现的,可能会受到Java单继承的限制。


四、应用场景


远程代理:在远程方法调用中,代理模式可以用于隐藏客户端和服务器之间的网络细节。客户端通过代理对象调用远程服务器的方法,代理对象负责处理网络通信、序列化和反序列化等细节。
虚拟代理:在创建开销较大的对象时,可以使用代理模式延迟对象的创建,直到真正需要使用它时才进行创建。例如,在图像加载时,可以使用虚拟代理来延迟加载图像资源,避免长时间的等待。
安全代理:代理模式可以用于控制对真实对象的访问权限。代理对象可以在调用真实对象的方法前进行权限检查,确保只有具有相应权限的用户才能访问真实对象。
缓存代理:代理模式可以用于缓存对象的方法调用结果。当多个客户端需要调用相同的方法时,代理对象可以在第一次调用时缓存方法的结果,以后的调用都直接返回缓存的结果,避免重复计算。
日志记录:代理模式可以用于记录方法的调用日志。代理对象可以在调用真实对象的方法前后记录日志信息,用于调试和分析应用程序的运行情况。

五、示例代码


以下是基于JDK动态代理的一个简单例子:

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
  
// 接口  
interface UserService {  
    void addUser();  
}  
  
// 实现类  
class UserServiceImpl implements UserService {  
    @Override  
    public void addUser() {  
        System.out.println("添加用户");  
    }  
}  
  
// 代理类  
class UserServiceProxy implements InvocationHandler {  
    private Object target;  
  
    public Object getProxy(Object target) {  
        this.target = target;  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);  
    }  
  
    @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 DynamicProxyTest {  
    public static void main(String[] args) {  
        UserService userService = new UserServiceImpl();  
        UserService proxy = (UserService) new UserServiceProxy().getProxy(userService);  
        proxy.addUser();  
    }  
}

运行测试类DynamicProxyTest,你将看到以下输出:

方法调用前

添加用户

方法调用后

我们定义了一个接口UserService和其实现类UserServiceImpl,然后定义了一个代理类UserServiceProxy,该类实现了InvocationHandler接口,并重写了其中的invoke方法。在invoke方法中,我们可以实现对真实对象的代理操作,如添加日志、权限检查等。最后,通过调用Proxy.newProxyInstance方法创建代理对象,并返回该代理对象。


http://www.kler.cn/news/362910.html

相关文章:

  • Docker 基础入门
  • 技术总结(十一)
  • 干货|基于React和xlsx库导出表格数据到excel(前端操作)
  • 【Qt】Qt的介绍——Qt的概念、使用Qt Creator新建项目、运行Qt项目、纯代码方式、可视化操作、认识对象模型(对象树)
  • SCCB协议与IIC协议不同
  • ICMP协议以及ARP欺骗攻击
  • 6.mysql安装【Docker】
  • Redis简介及其在NoSQL应用开发中的优化策略
  • blender 批量导入导出obj文件
  • 2024年华为OD机试真题-第k个排列-Python-OD统一考试(E卷)
  • 若依前后分离版集成积木报表
  • perl模式匹配修饰符
  • Linux-shell实例练习
  • 常用Python数据分析开源库:Numpy、Pandas、Matplotlib、Seaborn、Sklearn介绍
  • 六大知名Web安全漏洞靶场
  • AI虚拟主播之面部捕捉与生成!
  • 在linux上部署ollama+open-webu,且局域网访问教程
  • centos 和 Ubuntu 离线安装 lvm
  • 【Android】图片点击放大放小
  • 【数据结构与算法】之链表经典算法大集合
  • 2024.10.23 软考学习笔记(知识点)
  • 【1024程序员节】Mini-Omni2:实现具有视觉、语音和双工功能的开源 GPT-4o 模型
  • FPGA实现UDP通信(4)——数据接收实现
  • Hadoop 安装教程——单节点模式和分布式模式配置
  • freeswitch-esl动态控制录制音频(开始、停止)
  • 项目提测质量不高导致延期何解?