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

Java代理讲解

代理

代理模式是一种结构型设计模式,它允许我们通过添加一个代理对象来控制对另一个对象的访问。代理对象和实际对象具有相同的接口,使得客户端在不知情的情况下可以使用代理对象进行操作。代理对象在与客户端进行交互时,可以控制对实际对象的访问,以实现一些额外的功能,例如访问计数、延迟加载、权限控制等。

代理分为静态代理和动态代理两种

静态代理

静态代理是指在编译期间就已经确定代理类和被代理类的关系。代理类需要手动编写,并且每个被代理类都需要一个对应的代理类

特点

  • 编译期确定:在编译代码时,代理类的代码就已经确定,之后不会再发生变化。
  • 代码冗余:当有多个被代理类或者被代理类的方法很多时,会产生大量重复的代理代码。
  • 灵活性差:如果被代理类的接口发生变化,代理类也需要相应地修改。

 下边我们举一个例子帮助大家进行了解

使用接口进行静态代理

假设我们有一个叫cai的歌手,他只会进行singing和dance两件事情,但是当它要开演唱会时,他要进行收钱才开始操作,但是收钱这个操作他只会专心执行sing和dance这个操作或者说他不会首先这个操作。这时就需要它的经纪人来帮助他进行收钱操作(代理)

定义cai歌手

public class Cai implements Singer {@Overridepublic void singing() {System.out.println("cai 唱歌");}@Overridepublic int dance() {System.out.println("cai 跳舞");return 0;}
}

定义cai代理

public class Caidaili implements  Singer{private Singer cai = new Cai();@Overridepublic void singing() {System.out.println("先收钱");cai.singing();}@Overridepublic int dance() {System.out.println("先收钱");cai.dance();return 0;}
}

他们都要实现Singer这个接口(代理模式的核心思想是通过代理对象来控制对真实对象的访问,代理对象和真实对象需要对外提供一致的服务。接口定义了一组方法签名,实现同一个接口能保证代理对象和被代理对象具有相同的方法,客户端可以以相同的方式调用它们,从而实现对被代理对象的透明访问。)

public interface Singer {void singing();int dance();
}

最后使用main方法进行调用

public static void main(String[] args) {Singer singer = new Caidaili();singer.singing();singer.dance();}

此时来了一位新的歌手为wu,他同样会singing和dance,在假设其自己的方法和代理都实现时,我们只需要修改主代码中的代理对象即可实现

使用继承方式进行静态代理

同样的使用继承方式我们也可以实现上述操作

public class Singer {public void dance(){System.out.println("cai 跳舞");}public int singing(){System.out.println("cai 唱歌");return 100;}
}

 使用被代理类继承代理类

public class SingerSub extends Singer {@Overridepublic void dance() {System.out.println("收钱");super.dance();}@Overridepublic int singing() {System.out.println("收钱");return super.singing();}
}

 最后进行执行

public class Main {public static void main(String[] args) {Singer singer = new SingerSub();singer.singing();singer.dance();}
}

 

但是因为没有接口的实现,我们每次进行都要使用代理类来承接这个被代理类

结合上边的例子问题也随之出现,因为我们在代理类中实例化了被代理类,每一个被代理类都要一个代理类在其内部进行实例化,每出现一个被代理类都要生成一个新的代理类进行代理,极为不方便。

此时,我们就需要一个拥有强大业务能力的“经纪人”(动态代理),来代理所有的被代理对象,不用我们进行频繁的更换经纪人。

动态代理

从 静态代理 章节中为我们可知,静态代理存在着诸多的问题,最主要的问题是静态代理类需要对被代理类做手动的方法映射。造成这个问题的原因是代理对象是通过硬编码得到的,是在程序编译前就已经存在的,所以顺着这个思路,我们不难得到一个方向,如何代理对象不是通过硬编码提前写好的,而是在程序运行中动态生产的,且生成的代理对象可以对被代理类的方法做自动的映射,那么问题不就解决了吗?是的,这也就是动态代理的大致解决方案。

JDK代理(基于接口实现)

我们同样以上边的cai歌手的例子为例

定义一个Singer的接口

public interface Singer {void dance();int singing();
}

 创建一个cai歌手进行实现它

public class Cai implements Singer {@Overridepublic void dance() {System.out.println("Cai 在跳舞");}@Overridepublic int singing() {System.out.println("Cai 在唱歌");return 0;}
}

最后我们使用JDK代理来进行代理cai类

public static void main(String[] args) {Cai cai  = new Cai();//第一个参数:类加载器//第二个参数:代理类需要实现的接口数组//第三个参数:InvocationHandler接口,其中包含了一个invoke方法,该方法会在每次调用代理对象的方法时被触发Singer o = (Singer) Proxy.newProxyInstance(Cai.class.getClassLoader(), new Class[]{Singer.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if("singing".equals(method.getName())){System.out.println("先收钱");}else if("dance".equals(method.getName())){System.out.println("先收钱");}Object invoke = method.invoke(cai, args);//使用反射,将该方法作用到cai对象上return invoke;}});o.singing();}

 当我们想要修改被代理类,我们只需要修改

减少了,代理类的创建 

cglib代理(基于继承进行实现)

创建一个cai对象

public class Cai {public void dance(){System.out.println("cai 跳舞");}public String singing(){System.out.println("cai 唱歌");return "谢谢";}}

创建代理cai的方法

public class CreateCglibProxy {public static Object getProxy(Object o){Enhancer enhancer = new Enhancer();//生成代理对象enhancer.setSuperclass(o.getClass());//将代理对象设置为被代理对象的子类enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {if("singing".equals(method.getName())){System.out.println("先收钱");}else if("dance".equals(method.getName())){System.out.println("先收钱");}Object invoke = methodProxy.invokeSuper(proxyObject, args);return invoke;}});return enhancer.create();}
}

最后进行执行

public class Main {public static void main(String[] args) {Cai cai = new Cai();Cai proxy = (Cai) CreateCglibProxy.getProxy(cai);proxy.dance();}
}

相关文章:

  • 多层级的对象如何修改、或json格式
  • 回溯算法理论基础
  • Verilog 语法 (二)
  • 小刚说C语言刷题——1565成绩(score)
  • element-ui tabs 组件源码分享
  • 品融电商:以全域增长方法论,解码2025情绪消费新机遇
  • Coze高阶玩法 | 使用Coze制作思维认知提升视频,效率提升300%!(附保姆级教程)
  • OpenHarmony之电源管理子系统公共事件定义
  • Vue选项式 API 与组合式 API
  • jdk-8u202-linux-x64.tar.gz官方下载地址
  • 统计服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
  • 大学IP广播系统解决方案:构建数字化智慧化大学校园IP广播平台
  • 创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
  • Oracle Recovery Tools修复ORA-00742、ORA-600 ktbair2: illegal inheritance故障
  • 路由器的基础配置全解析:静态动态路由 + 华为 ENSP 命令大全
  • 3D模型文件格式之《STL格式介绍》
  • 知识蒸馏和迁移学习的区别
  • Cannot read properties of null (reading ‘classList‘)
  • A2A与MCP之间的简单理解
  • 【Google上包前APK自检】
  • 瞄准“美丽健康”赛道,上海奉贤如何打造宜居宜业之城?
  • 早睡1小时,变化有多惊人?第一个就没想到
  • 第1现场|无军用物资!伊朗港口爆炸已遇难40人伤1200人
  • 国家发改委答澎湃:力争6月底前下达2025年两重建设和中央预算内投资全部项目清单
  • 凝聚多方力量,中国农科院油菜产业专家团部署单产提升新任务
  • 王庆成:儒家、墨家和洪秀全的“上帝”