news 2026/9/3 5:36:27

Spring:代理模式之静态代理动态代理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring:代理模式之静态代理动态代理

前言

其实之前写过类似一篇了,重新具体的总结一下

代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 SpringMVC】面试必定

代理模式的分欸:

  • 静态代理
  • 动态代理

代理的原型:

静态代理

角色分析:

  • 抽象角色:一般会用接口或者抽象类来解决(这里指的是外卖平台和餐厅的共同目标”赚钱“)
  • 真实角色:被代理的角色(厨师、餐厅)
  • 代理角色:代理真实角色,代理真实角色后,通常会进行一些附属操作…(外卖平台)
  • 客户:访问代理对象的人!(这里指的是要吃饭的人)

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
  • 公共业务就交给了代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色,代码量翻倍~开发效率会变低
  • 缺点解决的办法就是动态代理

代码步骤

  1. 接口
// 卖吃的(赚钱)publicinterfaceSell{publicvoidsell();}
  1. 真实角色
// 厨师:真实角色publicclassChefimplementsSell{@Overridepublicvoidsell(){System.out.println("cike_y真实厨师:快来我这里点吃的吧");}}
  1. 代理角色
// 少用继承(局限性很大)、多用组合的方式publicclassproxyimplementsSell{@Overridepublicvoidsell(){System.out.println("外卖平台开始代理厨师的话:");chef.sell();//帮真实角色(厨师)代理他说的话// 下面是外卖平台(中介代理)的附属操作System.out.println("外卖平台(中介代理)开始附属以下操作了:\n");SeeRider();SendOrder();GiveMoney();TakeCommission();TakeRiderFee();}// 组合privateChefchef;publicproxy(){}publicproxy(Chefchef){this.chef=chef;}// setProxy(){..} 没必要set注入// 代理可以做一些附属的事情publicvoidSeeRider(){// 找骑手System.out.println("帮你寻找骑手中……");}// 收取佣金publicvoidTakeCommission(){System.out.println("外卖平台收取佣金");}// 骑手费用publicvoidTakeRiderFee(){System.out.println("给骑手小费");}// 发送客户订单publicvoidSendOrder(){System.out.println("发送客户订单");}// 给餐厅钱publicvoidGiveMoney(){System.out.println("给餐厅钱");}}
  1. 客户端访问代理角色
publicclassClient{publicstaticvoidmain(String[]args){// 想点这家餐厅做的菜Chefchef=newChef();// 外卖平台,帮你通知厨师做菜,但是外卖平台(代理)会做一些附属操作proxy proxy=newproxy(chef);// 你不用面对厨师、直接找外卖平台即可!proxy.sell();}}

加深理解

在一个增删改查的业务

  1. 接口类(公共调用的方法)
publicinterfaceUserService{publicvoidadd();publicvoiddelete();publicvoidupdate();publicvoidquery();}
  1. 真实角色(业务实现类)
publicclassUserServiceImpl{publicvoidadd(){System.out.println("添加用户");}publicvoiddelete(){System.out.println("删除用户");}publicvoidupdate(){System.out.println("修改用户");}publicvoidquery(){System.out.println("查询用户");}}
  1. 代理角色(代理真实角色的类&横向扩展附属操作)
publicclassUserServiceProxyimplementsUserService{publicUserServiceProxy(UserServiceImpluserServiceImpl){this.userServiceImpl=userServiceImpl;}publicvoidsetUserServiceImpl(UserServiceImpluserServiceImpl){this.userServiceImpl=userServiceImpl;}privateUserServiceImpluserServiceImpl;@Overridepublicvoidadd(){debug("add");userServiceImpl.add();}@Overridepublicvoiddelete(){debug("delete");userServiceImpl.delete();}@Overridepublicvoidupdate(){debug("update");userServiceImpl.update();}@Overridepublicvoidquery(){debug("query");userServiceImpl.query();}// 日志方法:横向扩展增增删改查业务publicvoiddebug(Stringmsg){System.out.println("debug:"+msg+"方法执行了");}}
  1. 客户端访问代理角色(客户端想实现真实角色的类,只能通过访问代理角色)
publicclassClient{publicstaticvoidmain(String[]args){UserServiceImpluserServiceImpl=newUserServiceImpl();UserServiceProxyuserServiceProxy=newUserServiceProxy(userServiceImpl);userServiceProxy.add();userServiceProxy.delete();userServiceProxy.update();userServiceProxy.query();}}

聊聊AOP:

动态代理

动态代理的底层都是反射

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口的—JDK的动态代理【我们在这里使用】
    • 基于类:cglib
    • java字节码实现:javasist

需要了解的两个类:Proxy:代理,InvocationHandler:调用处理程序

Proxy

  • Proxy提供了创建动态代理类和实例的静态方法。

InvocationHandler

  • 代理实例的_调用处理程序_实现的_接口_

代理类写法

  1. 继承InvocationHandler接口
publicclassProxyInvocationHandlerimplementsInvocationHandler
  1. 引用真实角色的接口
privateSellsell;
  1. 获取真实角色的共同继承的接口
publicObjectgetProxy(){// 获取被代理接口的所有方法returnProxy.newProxyInstance(this.getClass().getClassLoader(),sell.getClass().getInterfaces(),this);}
  1. 处理代理实例,并且执行方法返回结果
// 处理代理实例,并返回结果publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectresult=method.invoke(sell,args);// 执行一个方法,执行完毕之后会获取一个结果returnresult;}

代码步骤

真实角色(厨师)

// 厨师:真实角色publicclassChefimplementsSell{@Overridepublicvoidsell(){System.out.println("cike_y真实厨师:这里是Demo04案例,快来我这里点吃的吧");}}

外卖平台和厨师都要赚钱(共同接口)

publicinterfaceSell{publicvoidsell();}

外卖平台(动态代理类)

//等我们会用这个类自动生成代理类!publicclassProxyInvocationHandlerimplementsInvocationHandler{// 被代理的接口,解耦性强privateSellsell;publicvoidsetSell(Sellsell){this.sell=sell;}// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),// new Class<?>[] { Foo.class },// handler);// 获取真实角色和代理角色公共的接口publicObjectgetProxy(){// 获取被代理接口的所有方法returnProxy.newProxyInstance(this.getClass().getClassLoader(),sell.getClass().getInterfaces(),this);}// 处理代理实例,并返回结果publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{// 在执行目标对象的方法之前,可以进行一些自定义操作Start();Objectresult=method.invoke(sell,args);// 执行一个方法,执行完毕之后会获取一个结果// 在执行目标对象的方法之后,可以进行一些自定义操作SeeRider();SendOrder();GiveMoney();TakeCommission();TakeRiderFee();returnresult;}// 代理的附属操作publicvoidStart(){System.out.println("这里是外卖平台,开始代理:");}// 代理可以做一些附属的事情publicvoidSeeRider(){// 找骑手System.out.println("帮你寻找骑手中……");}// 收取佣金publicvoidTakeCommission(){System.out.println("外卖平台收取佣金");}// 骑手费用publicvoidTakeRiderFee(){System.out.println("给骑手小费");}// 发送客户订单publicvoidSendOrder(){System.out.println("发送客户订单");}// 给餐厅钱publicvoidGiveMoney(){System.out.println("给餐厅钱");}}

用户(要吃饭的人:面对外卖平台)

publicclassClient{publicstaticvoidmain(String[]args){// 真实角色Chefchef=newChef();// 代理角色ProxyInvocationHandlerproxyInvocationHandler=newProxyInvocationHandler();// 要代理的对象:指的是真实角色,设置代理的真实角色对象proxyInvocationHandler.setTarget(chef);// 代理角色(已经代理了真实角色了)获取接口Sellproxy=(Sell)proxyInvocationHandler.getProxy();// 直接面对外卖平台,不用找厨师proxy.sell();}

万能的写法

只需要改变动态代理的对象为Object对象就可以了,因为Java 中Object 类是所有类的父类,也就是说Java 的所有类都继承了Object,子类可以使用Object 的所有方法。

publicclassProxyInvocationHandlerimplementsInvocationHandler{// 要代理的接口privateObjecttarget;publicvoidsetTarget(Objecttarget){this.target=target;}// 官方写法:// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),// new Class<?>[] { Foo.class },// handler);// 获取真实角色的公共接口publicObjectgetProxy(){returnProxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}// 处理代理实例,并返回结果publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectresult=method.invoke(target,args);// 执行方法,返回结果returnresult;}}

其余的:真实角色(厨师)、接口(外卖平台和厨师的共同目标)、用户(吃饭的人)写法都不需要变。

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
  • 公共业务就交给了代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

参考文档:

JDK-api-1.8_google
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 21:54:29

动作自然流畅:motion_scale保持1.0-1.1防止夸张变形

动作自然流畅&#xff1a;motion_scale保持1.0-1.1防止夸张变形 在虚拟主播24小时不间断带货、AI教师批量生成教学视频的今天&#xff0c;数字人早已不再是影视特效工作室的专属产物。随着Sonic这类轻量级口型同步模型的出现&#xff0c;仅凭一张照片和一段音频就能生成逼真说话…

作者头像 李华
网站建设 2026/9/2 21:01:50

调用频率控制:限制单个账号每秒请求Sonic次数

调用频率控制&#xff1a;限制单个账号每秒请求Sonic次数 在数字人内容爆发式增长的今天&#xff0c;只需一张照片和一段音频就能生成逼真“虚拟主播”的技术已不再是科幻。腾讯联合浙江大学推出的轻量级口型同步模型 Sonic&#xff0c;正悄然改变着短视频创作、在线教育乃至电…

作者头像 李华
网站建设 2026/9/2 6:32:09

大数据领域数据目录的版本管理与更新策略

大数据领域数据目录的版本管理与更新策略&#xff1a;从原理到实战 在大数据时代&#xff0c;企业的数据资产正以指数级速度增长——每天产生的日志、交易记录、用户行为数据被存入数据湖/数据仓库&#xff0c;衍生出数百张分析表、数十个BI报表和机器学习模型。然而&#xff0…

作者头像 李华
网站建设 2026/9/3 0:30:05

亲测好用8个AI论文平台,MBA轻松搞定毕业论文!

亲测好用8个AI论文平台&#xff0c;MBA轻松搞定毕业论文&#xff01; AI 工具如何助力 MBA 撰写高质量论文 MBA 学生在撰写毕业论文时&#xff0c;常常面临时间紧张、内容繁杂、逻辑梳理困难等问题。而随着 AI 技术的不断成熟&#xff0c;越来越多的 AI 工具被引入到学术写作…

作者头像 李华
网站建设 2026/9/3 3:12:53

lora监督微调(SFT)

前提conda 环境和安装包都得安装好&#xff1a; conda create -n qwen310 python3.10 -y conda activate qwen310 pip install -U pip# 临时使用清华源装通用包 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -U transformers accelerate sentencepiece tokenizer…

作者头像 李华
网站建设 2026/9/2 21:02:41

关于图表,对理解IT系统业务流程设计的辅助作用

我们设计这个IT系统&#xff0c;最后肯定是要作用于用户的&#xff0c;没人用。 那这个系统&#xff0c;设计出来。 对于不是编码实现。 就是设计、给人用的IT系统&#xff0c;我们从什么方向和角度去认识。 引言&#xff1a; 一个很好地方向&#xff1a; 核心功能的时序图。 我…

作者头像 李华