你管这叫代理模式(Proxy Pattern)

简介: 代理模式即给一个真实类提供一个代理类,该代理类代替真实类完成其功能,一般还可在代理类上添加一些真实类不具有的附加功能,通俗来讲代理模式就是我们生活中常见的中介,代理模式又可分为静态代理和动态代理。

代理模式


  代理模式即给一个真实类提供一个代理类,该代理类代替真实类完成其功能,一般还可在代理类上添加一些真实类不具有的附加功能,通俗来讲代理模式就是我们生活中常见的中介,代理模式又可分为静态代理动态代理


静态代理


  静态代理需要代理类和目标类实现一样的接口,一般将被代理对象组合到代理类中,然后使用其完成对应功能,并可在代理类中添加额外功能。


租房静态代理过程

第一步:创建服务接口

public interface Rent {
// 出租房屋
void rent();
}


第二步:真实类实现服务接口

public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子...");
}
}


第三步:代理类实现服务接口

public class Proxy implements Rent{
// 被代理的类,用于完成被代理类功能。
private Host host;
// 用于初始化被代理类
public void setHost(Host host) {
this.host = host;
}
// 完成被代理类的功能,同时可附加其他功能。
@Override
public void rent() {
doSomething();
host.rent();
doSomething();
}
// 附加的功能
private void doSomething() {
System.out.println("doSomething...");
}
}


第四步:编写测试类

public class Test {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy();
proxy.setHost(host);
proxy.rent();
}
}


静态代理总结


优点

  • 高扩展性:可以在不修改目标类的前提下扩展目标类的功能。

缺点

  • 冗余:一个目标类就会产生一个代理类,会产生过多的代理类。
  • 开发效率低:代理类代码量繁重。
  • 不易维护:一旦接口改变,目标类与代理类都要进行修改。


动态代理


  动态代理中我们不需要手动的创建代理类,只需要编写一个动态处理器来为我们动态创建代理对象,代理对象由 JDK 在运行时动态创建,动态代理基于反射来实现


常用的动态代理方式


  • 基于接口的动态代理:由 JDK 提供,使用 JDK 官方的 Proxy 类创建代理对象。
  • 基于类的动态代理:由第三方 CGLib 提供,使用 CGLib Enhancer 类创建代理对象
  • javassist
  • ……


基于接口的动态代理


  使用基于接口的动态代理首先需要了解 JDK 中的 Proxy 类和 InvocationHandler接口,然后用其编写动态处理器用于完成动态代理。


Proxy


  Proxy 提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
  
一般使用 Proxy newProxyInstance 静态方法创建代理类,需要提供一个类加载器、被代理类的服务接口,以及一个 InvocationHandler 的对象。

  • 类加载器:用于加载类和接口
  • 被代理类的接口:提供被代理类服务接口信息
  • InvocationHandler 对象:用于执行被代理类的方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h);


InvocationHandler 接口


  当在代理实例上调用方法时,方法调用被编码并分派到其调用处理程序的调用方法,即在 Proxy 中调用方法时,该方法调用被分派给 InvocationHandler 对象中的 invoke 方法执行,由 invoke 方法调用执行被代理对象的方法。

Object invoke(Object proxy, Method method, Object[] args);


动态处理器工具类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target;
public ProxyInvocationHandler() {
}
public ProxyInvocationHandler(Object target) {
this.target = target;
}
// 用于初始化被代理类
public void setTarget(Object target) {
this.target = target;
}
// 生成得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// 处理代理示例并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}


基于接口的租房动态代理过程

第一步:创建服务接口

public interface Rent {
// 出租房屋
void rent();
}


第二步:真实类实现服务接口

public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子...");
}
}


第三步:编写动态处理器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target;
// 用于初始化被代理类
public void setTarget(Object target) {
this.target = target;
}
// 生成得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// 处理代理示例并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomething();
Object invoke = method.invoke(target, args);
doSomething();
return invoke;
}
// 附加的功能
private void doSomething() {
System.out.println("doSomething...");
}
}


第四步:编写测试类

public class Test {
public static void main(String[] args) {
Host host = new Host();
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setTarget(host);
Rent proxy = (Rent)proxyInvocationHandler.getProxy();
proxy.rent();
}
}


动态代理总结

优点

  • 高扩展性:可以在不修改目标类的前提下扩展目标类的功能。
  • 低冗余:会产生过多的代理类。
  • 低耦合:减少了对业务接口的依赖。
  • 高效开发:大大减少开发任务,一个动态处理器即可完成代理。


注意事项

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制

相关文章
|
存储 缓存 算法
Linux 的 workqueue 机制浅析
## Intro workqueue 是 Linux 中非常重要的一种异步执行的机制,本文对该机制的各种概念,以及 work 的并行度进行分析,以帮助我们更好地**使用**这一机制;对 workqueue 机制并不陌生的读者也可以直接跳到第四节,即 "Concurrency" 小节,了解 workqueue 机制中 work 的并行度 以 v2.6.36 为界,workqueue 存在两个不
2631 0
Linux 的 workqueue 机制浅析
|
4月前
|
人工智能 Linux API
OpenClaw 阿里云/本地部署无人值守社媒内容流水线实战:+Skills全自动生成公众号+小红书草稿教程
在日常公众号、小红书内容运营中,大量时间消耗在素材搜集、选题整理、初稿撰写、格式排版等重复工作上。借助OpenClaw(Clawdbot)的Skill体系与任务调度能力,可搭建一套无人值守、每日自动运行的社媒内容流水线:AI自动抓取灵感、生成选题、撰写公众号长文草稿、输出小红书图文笔记,并按日期归档保存,人工仅需最后润色即可发布。本文基于2026年最新环境,完整提供阿里云服务器、本地MacOS/Linux/Windows11部署流程、阿里云百炼通义千问API配置、免费大模型Coding Plan对接、四大核心Skill开发、Python脚本保存草稿、定时任务设置及高频问题一站式解答,所有代码可
687 2
|
8月前
|
数据采集 人工智能 大数据
2025年数据治理工具哪家好?国内数据治理厂商推荐
围绕当前市场需求,对多款主流数据治理工具进行详细解析,为企业IT及数据管理相关部门员工提供有价值的参考,助力企业精准选择数据治理解决方案。
|
Java
SpringBoot启动报错org.apache.catalina.LifecycleException
SpringBoot启动报错org.apache.catalina.LifecycleException
315 0
|
12月前
|
JSON 缓存 监控
1688商品详情API实时数据解析的示例
1688商品详情API可实时获取商品标题、价格、规格、库存等核心数据。通过商品ID调用接口,支持解析基础信息、SKU规格、卖家与物流详情。提供Python调用示例与完整数据解析逻辑,适用于采购比价、供应商监控等场景,确保数据精准获取与处理。
|
机器学习/深度学习 存储 人工智能
AI歌姬,C位出道,基于PaddleHub/Diffsinger实现音频歌声合成操作(Python3.10)
懂乐理的音乐专业人士可以通过写乐谱并通过乐器演奏来展示他们的音乐创意和构思,但不识谱的素人如果也想跨界玩儿音乐,那么门槛儿就有点高了。但随着人工智能技术的快速迭代,现在任何一个人都可以成为“创作型歌手”,即自主创作并且让AI进行演唱,极大地降低了音乐制作的门槛。 本次我们基于PaddleHub和Diffsinger实现音频歌声合成操作,魔改歌曲《学猫叫》。
AI歌姬,C位出道,基于PaddleHub/Diffsinger实现音频歌声合成操作(Python3.10)
|
Kubernetes 安全 Docker
K8S集群部署
K8S集群部署
443 0
RTMP协议详解及Wiresahrk抓包分析(三)
RTMP协议详解及Wiresahrk抓包分析
634 1
|
监控 Java API
使用Spring Boot构建微服务架构的最佳实践
使用Spring Boot构建微服务架构的最佳实践
|
Dart 算法 数据可视化
用flutter实现五种寻路算法的可视化效果,快来看看!
半年前我写了一篇有关排序算法可视化的文章,挺有意思,还被张风捷特烈-张老师收录进了FlutterUnit,今天让我们再来做一个有关寻路算法的可视化效果吧!