Java学习:动态代理的一点小理解

手动实现#

之前的一篇讲IoC的博文提到了代理模式,事实上代理模式就是AOP实现的重要基石。但是上面的代码有一个显而易见的缺陷,也就是之前讲解反射内容时提到的:不具备动态性

上面代码中的Server就像是反射理解博文中提到的工厂订单管理员一样,每增加一样菜系,就需要相应更新手上的菜单。类比反射特性,我们完全可以做到让服务员不需要手上拿着菜单来为顾客服务:

Copy
// 服务员实现类 public class ServerImpl implements Server { // 采用组合的方式引入noodles private Noodles noodles; @Override public void getNoodles() { // 代理模式 noodles.getNoodles(); } // 利用反射特性 @Override public void setNoodles(String noodles) { this.noodles = (Noodles) Class.forName(noodles).newInstance(); } } }

API实现#

之前的动态代理是我们手动实现的,JDK其实自带了很多实现动态代理的类和方法。可能初次接触时会显得有些复杂,所以先画一张图来表示我们整个的设计思路:

https://gitee.com/acctzcw/pictures/raw/master/Java%E5%AD%A6%E4%B9%A0/Java_Spring/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E7%A4%BA%E4%BE%8B.png

之前在讨论IoC举的餐馆用例中,除了不具备动态性之外还有一个缺陷:服务员只服务于本餐馆,也就是说,我们能不能把服务员这个群体抽离出来,不仅服务这个餐馆,也能服务于多家餐馆,以实现代码的复用呢?

现实生活中有一种类型的公司,叫做家政公司,我们可以类比来编写一个服务员工厂:

Copy
public class ServerFactory implements InvocationHandler { private Object target; // 设定服务对象 public void setTarget(Object target) { this.target = target; } // 返回单个服务员 public Object getServer() { 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); } }

这是利用java.lang.reflect包提供的动态代理相关类和方法编写的ServerFactory。最后的invoke方法是继承接口要求的重写方法,不妨碍我们理解,暂时忽略,主要关注前半部分的代码。

前半部分代码非常好理解:

  1. 工厂接到业务需求:给某某提供服务。派出服务团队
  2. 利用setTarget确定服务对象。
  3. 使用getServer返回对应的服务人员。

下面使用这个类进行测试,同样以与餐馆厨师对接为例:

Copy
public class ServerTest { public static void main(String[] args) { // 获取服务员团队 ServerFactory serverGroup = new ServerFactory(); // 设定该团队对接面食厨师 serverGroup.setCooker(new NoodleCooker()); // 获取单个服务员 Cooker server = (Cooker) serverGroup.getServer(); // 顾客点餐 server.cooking(); } } // NoodleCooker类 public class NoodleCooker implements Cooker { @Override public void cooking() { System.out.println("开始下面了!"); } } // Cooker接口 public interface Cooker { void cooking(); }

我们实现了服务员和餐馆之间的解耦。有了服务员工厂,可以给任意的客户提供专业服务团队(setTarget),并且为每一次服务需求提供单个服务员进行实现(getServer)。

Proxy的实现#

探讨一下java中Proxy实现的大概机理,主要是针对invoke方法的理解。

根据反射的相关知识我们知道,invoke方法是Method类的方法,而Method类的对象是包含在class对象内部的,代表类的方法信息。invoke方法本质上是驱动某一个实例来调用method:

Copy
public class Person{ public int eat(String name){ System.out.println("eating..."); return 1; } } // method是eat方法的实例 Person jojo = new Person(); Method method = jojo.getClass().getMethod("eat"); int result = method.invoke(jojo,"Jonathan"); // 等价于 int result = jojo.eat("Jonathan");

由此大概可以想到Proxy是怎么实现代理的了:

  1. 开始执行server.cooking()
  2. 读取NoodleCooker.class中cooking的method实例
  3. 将method实例和server.cooking()的参数传入ServerFactory.invoke()
  4. 执行invoke内部的代码
  5. server.cooking执行完毕
posted @   _acct  阅读(178)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
CONTENTS