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

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();}
}

http://www.xdnf.cn/news/1936.html

相关文章:

  • 常见网络安全攻击类型深度剖析(三):DDoS攻击——分类、攻击机制及企业级防御策略
  • AI编程:[体验]从 0 到 1 开发一个项目的初体验
  • 利用车联网中的 V2V 通信技术传播公平的紧急信息
  • 【深度强化学习 DRL 快速实践】异步优势演员评论员算法 (A3C)
  • PCIe具体解释分析
  • 【基础IO上】复习C语言文件接口 | 学习系统文件接口 | 认识文件描述符 | Linux系统下,一切皆文件 | 重定向原理
  • 【kafka初学】启动执行命令
  • c#操作excel表格
  • Java与Kotlin在Android开发中的全面对比分析
  • 【Luogu】动态规划四
  • Hot100方法及易错点总结2
  • firewalld 详解
  • 微信小程序蓝牙连接打印机打印单据完整Demo【蓝牙小票打印】
  • 【prompt是什么?有哪些技巧?】
  • Linux操作系统复习
  • 3D模型文件格式之《STL格式介绍》
  • SSH服务介绍
  • string的基本使用
  • uniapp自定义封装tabbar
  • 探索亚马逊云科技:开启您的云计算之旅
  • Safety Estimands与Efficacy Estimands的差异剖析
  • 模式设计简介
  • 北斗导航 | 北斗卫星导航单点定位精度提升方法总结,原理,公式,关键代码
  • 架构师面试(三十六):广播消息
  • websheet 之 sheet操作
  • c++11新特性随笔
  • 使用开源免费雷池WAF防火墙,接入保护你的网站
  • Shell 脚本入门:从零开始写自动化脚本
  • 代码随想录算法训练营day11(二叉树)
  • 轻量级静态网站托管:服务器配置与网站性能深入探讨