news 2026/4/18 8:38:24

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/4/18 8:19:44

小白也能上手:图文详解VoxCPM-1.5-TTS模型一键部署流程

小白也能上手&#xff1a;图文详解VoxCPM-1.5-TTS模型一键部署流程 你有没有想过&#xff0c;只需要点一下脚本&#xff0c;就能让电脑“开口说话”&#xff1f;而且声音自然得像真人朗读一样——这不再是科幻电影的桥段&#xff0c;而是今天任何普通用户都能亲手实现的技术现…

作者头像 李华
网站建设 2026/4/17 4:03:46

三相电机容错控制:电流预测算法的奇妙旅程

三相电机容错控制&#xff0c;采用电流预测算法在电机控制领域&#xff0c;三相电机因其高效、稳定等优点被广泛应用。然而&#xff0c;电机运行过程中难免会遭遇各种故障&#xff0c;这时候容错控制就显得尤为重要。今天咱就来唠唠三相电机容错控制里的电流预测算法&#xff0…

作者头像 李华
网站建设 2026/4/18 8:16:04

鸿蒙开发语言ArkTS全面介绍

一、ArkTS语言概述与定位 ArkTS&#xff08;Ark TypeScript&#xff09;是华为专为鸿蒙操作系统&#xff08;HarmonyOS&#xff09;生态打造的应用开发语言&#xff0c;作为TypeScript的超集&#xff0c;它在继承TypeScript语法特性的基础上&#xff0c;针对鸿蒙生态进行了深度…

作者头像 李华
网站建设 2026/4/16 13:11:31

《创业之路》-792-产品有哪些常见的关键技术指标? 个人有哪些关键的绩效指标?企业经验有哪些关键绩效指标? 给出示例

以下是针对产品、个人、企业三类主体的常见关键技术指标&#xff08;Key Technical Indicators&#xff09;与关键绩效指标&#xff08;KPI&#xff09; 的系统性梳理&#xff0c;包含定义、用途和具体示例&#xff0c;帮助实现目标对齐与价值衡量。一、产品的常见关键技术指标…

作者头像 李华
网站建设 2026/4/17 7:57:46

《创业之路》-794-对于相同的现实问题,中底层管理者关注当下、内部、成本、效率、战术、营收、一次性;高层管理者关注未来、外部、资本、价值、战略、竞争性、持续性。

这句话极具洞察力&#xff0c;精准概括了不同管理层级在思维方式、关注重点与决策逻辑上的根本差异。以下是对此观点的系统性深化、结构化表达与思想延展&#xff0c;适用于组织管理、领导力培训或战略沟通场景&#xff1a;&#x1f310; **对于相同的现实问题&#xff0c;中底…

作者头像 李华