java高级——动态代理

目录

  • 动态代理介绍
  • 明星代理案例实现
  • 案例分析
  • 动态代理应用场景

动态代理介绍

用一个明星的案例来解释动态代理的流程。

  1. 假设现在有一个明星坤坤,它有唱歌和跳舞的本领,作为明星是要用唱歌和跳舞来赚钱的。
  2. 但是每次做节目,唱歌的时候要准备话筒、收钱,再唱歌;跳舞的时候也要准备场地、收钱、再唱歌。
  3. 明星觉得我擅长的做的事情是唱歌,和跳舞,但是每次唱歌和跳舞之前或者之后都要做一些繁琐的事情,有点烦。
  4. 于是就找个一个经济公司,请了一个代理人,代理明星处理这些事情,如果有人想请明星演出,直接找代理人就可以了。

20240227-010757-T4.png

明星代理案例实现

根据上面的案例,可以设计一个大明星对象,来表示大明星的职责是唱歌和跳舞;声明一个明星接口来声明大明星类中有的方法代理对象也会有,大明星对象实现明显接口。

  1. 明星接口
public interface Star {String sing(String name);void dance();
}
  1. 大明星对象
public class BigStar implements Star{private String name;public BigStar(String name) {this.name = name;}public String sing(String name){System.out.println(this.name + "正在唱:" + name);return "谢谢!谢谢!";}public void dance(){System.out.println(this.name  + "正在优美的跳舞~~");}
}
  1. 生成动态代理对象
    有了上面的准备工作,需要写一个为BigStar生成动态代理对象的工具类ProxyUtil代表中介机构。使用工具类产生代理则需要用Java为开发者提供的一个生成代理对象的类叫Proxy类。注意Proxy类有多个,我们需要选择java.lang.reflect中的Proxy

通过Proxy类的newInstance(…)方法可以为实现了同一接口的类生成代理对象。 调用方法时需要传递三个参数,该方法的参数解释可以查阅API文档,如下
20240227-012000-Qo.png


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {public static Star createProxy(BigStar bigStar){/* newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)参数1:用于指定一个类加载器参数2:指定生成的代理长什么样子,也就是有哪些方法参数3:用来指定生成的代理对象要干什么事情*/// Star starProxy = ProxyUtil.createProxy(s);// starProxy.sing("好日子") starProxy.dance()Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{Star.class}, new InvocationHandler() {@Override // 回调方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 代理对象要做的事情,会在这里写代码if(method.getName().equals("sing")){System.out.println("准备话筒,收钱20万");}else if(method.getName().equals("dance")){System.out.println("准备场地,收钱1000万");}return method.invoke(bigStar, args);}});return starProxy;}
}
  1. 写一个Test类调用我们写好的ProxyUtil工具类,为BigStar对象生成代理对象
public class Test {public static void main(String[] args) {BigStar s = new BigStar("大明星坤坤");Star starProxy = ProxyUtil.createProxy(s);String rs = starProxy.sing("好日子");System.out.println(rs);starProxy.dance();}
}
  1. 运行结果如下
    20240227-012407-TG.png

案例分析

Proxy类的newInstance(…)方法

newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
参数1:用于指定一个类加载器 用于加载生成的代理类 写法是固定的 背就行 一般用当前类的类加载器参数2:一个接口数组 指定生成的代理长什么样子 也就是有哪些方法 我们这里只有一个接口 把它包装成数组传进去即可参数3:用来指定生成的代理对象要干什么事情 这里传递的是一个InvocationHandler接口,因为接口不能直接创建对象 所以一般是传递一个匿名内部类对象来指定代理对象干什么事情重写invoke方法就行

Proxy代理对象的执行流程

nvoke方法是个回调方法 会被谁回调呢? 
1. 假设代理写好了调用时是会写这样的代码的:
//得到一个s的代理对象
Star starProxy = ProxyUtil.createProxy(s);
starProxy.sing("好日子")
starProxy.dance()
2. 这两个sing和dance方法会调用invoke方法!
因为代理干什么事情用invoke决定,invoke需要三个参数,所以sing和dance也会传进这三个参数
比如starProxy.sing("好日子") starProxy是第一个参数,sing是第二个,"好日子"是第三个
第一个参数java把代理对象当做一个Object:也就是starProxy
第二个参数是调用的方法:如果是sing调用 method代表的就是sing方法
第三个参数args:会把方法的参数通过一个object数组传进来(比如sing调用时就会把"好日子"传进数组)
这就是invoke三个参数的含义

动态代理应用场景

某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。

现有如下代码:
用户业务接口UserService

/***  用户业务接口*/
public interface UserService {// 登录功能void login(String loginName,String passWord) throws Exception;// 删除用户void deleteUsers() throws Exception;// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;
}

用户业务实现类UserServiceImpl

/*** 用户业务实现类(面向接口编程)*/
public class UserServiceImpl implements UserService {@Overridepublic void login(String loginName, String passWord) throws Exception {long time1 = System.currentTimeMillis();if ("admin".equals(loginName) && "123456".equals(passWord)) {System.out.println("您登录成功,欢迎光临本系统~");} else {System.out.println("您登录失败,用户名或密码错误~");}Thread.sleep(1000);long time2 = System.currentTimeMillis();System.out.println("login方法耗时:" + (time2 - time1) / 1000.0 + "s");}@Overridepublic void deleteUsers() throws Exception {long time1 = System.currentTimeMillis();System.out.println("成功删除了1万个用户~");Thread.sleep(1500);long time2 = System.currentTimeMillis();System.out.println("deleteUsers方法耗时:" + (time2 - time1) / 1000.0 + "s");}@Overridepublic String[] selectUsers() throws Exception {long time1 = System.currentTimeMillis();System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};Thread.sleep(500);long time2 = System.currentTimeMillis();System.out.println("selectUsers方法耗时:" + (time2 - time1) / 1000.0 + "s");return names;}
}

会发现每一个方法中计算耗时的代码都是重复的,况且这些重复的代码并不属于UserSerivce的主要业务代码。所以接下来可以把把计算每一个方法的耗时操作,交给代理对象来做。

先在UserService类中把计算耗时的代码删除,代码如下

public class UserServiceImpl implements UserService {@Overridepublic void login(String loginName, String passWord) throws Exception {if ("admin".equals(loginName) && "123456".equals(passWord)) {System.out.println("您登录成功,欢迎光临本系统~");} else {System.out.println("您登录失败,用户名或密码错误~");}Thread.sleep(1000);}@Overridepublic void deleteUsers() throws Exception {System.out.println("成功删除了1万个用户~");Thread.sleep(1500);}@Overridepublic String[] selectUsers() throws Exception {System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};Thread.sleep(500);return names;}
}

然后为UserService生成一个动态代理对象,在动态代理中调用目标方法,在调用目标方法之前和之后记录毫秒值,并计算方法运行的时间。代码如下

public class ProxyUtil {public static UserService creatProxy(UserService userService){UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{UserService.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName=method.getName();if(methodName.equals("login")||methodName.equals("deleteUsers")||methodName.equals("selectUsers")){long startTime = System.currentTimeMillis();Object rs = method.invoke(userService,args);long endTime = System.currentTimeMillis();System.out.println(methodName + "方法执行耗时:"+(endTime-startTime)/1000.0+"s");return rs;}else{Object rs = method.invoke(userService,args);return rs;}}});return userServiceProxy;}
}

在测试类中为UserService创建代理对象:

public class Test {public static void main(String[] args) throws Exception{// 1、创建用户业务对象。UserService userService = ProxyUtil.createProxy(new UserServiceImpl());// 2、调用用户业务的功能。userService.login("admin", "123456");System.out.println("----------------------------------");userService.deleteUsers();System.out.println("----------------------------------");String[] names = userService.selectUsers();System.out.println("查询到的用户是:" + Arrays.toString(names));System.out.println("----------------------------------");}
}

执行结果如下所示:
20240227-015521-Dg.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/708759.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云2024年服务器2核4G配置评测_CPU内存带宽_优惠价格

阿里云2核4G服务器多少钱一年&#xff1f;2核4G服务器1个月费用多少&#xff1f;2核4G服务器30元3个月、85元一年&#xff0c;轻量应用服务器2核4G4M带宽165元一年&#xff0c;企业用户2核4G5M带宽199元一年。本文阿里云服务器网整理的2核4G参加活动的主机是ECS经济型e实例和u1…

卢森堡比利时土耳其媒体宣发稿助力跨境出海推广新闻营销

【本篇由言同数字科技有限公司原创】随着全球化进程的加速&#xff0c;越来越多的品牌开始考虑在海外市场扩展业务。对于品牌来说&#xff0c;跨境海外推广是必要的&#xff0c;因为它可以帮助品牌打开更大的市场、吸引更多的消费者、提高品牌知名度和形象&#xff0c;并在全球…

Linux磁盘性能方法以及磁盘io性能分析

Linux磁盘性能方法以及磁盘io性能分析 1. fio压测1.1. 安装fio1.2. bs 4k iodepth 1&#xff1a;随机读/写测试&#xff0c;能反映硬盘的时延性能1.3. bs 128k iodepth 32&#xff1a;顺序读/写测试&#xff0c;能反映硬盘的吞吐性能 2. dd压测2.1. 测试纯写入性能2.2. 测试…

MurmurHash算法

MurmurHash&#xff1a;(multiply and rotate) and (multiply and rotate) Hash&#xff0c;乘法和旋转的hash 算法。 一、哈希函数 散列函数&#xff08;英语&#xff1a;Hash function&#xff09;又称散列算法、哈希函数&#xff0c;是一种从任何一种数据中创建小的数字“…

抖音小店新店没有体验分怎么办?怎么从零做体验分?新手商家速看

大家好&#xff0c;我是电商花花。 新手开店的体验分都不是很高&#xff0c;我们想要做店铺体验分都要从零开始做。 如果新手开店不需要怎么出体验分&#xff0c;不知道怎么提高店铺体验分的&#xff0c;都可以看一下今天的文章&#xff0c;教大家怎么做店铺的体验分。 首先&…

基于springboot + vue实现的前后端分离-汽车票网上预定系统(项目 + 论文)

项目介绍 系统是一个B/S模式系统&#xff0c;采用Spring Boot框架&#xff0c;MySQL 数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得汽车票网上预订系统管理工作系统化、规范化。本系统的使用使管理人…

JVM——JVM与Java体系结构

文章目录 1、Java及JVM简介1.1、Java是跨平台的语言1.2、JVM是跨语言的平台 2、Java发展里程碑3、Open JDK和Oracle JDK4、虚拟机与JVM4.1、虚拟机4.2、JVM 5、JVM整体结构6、Java代码执行流程7、JVM的架构模型7.1、基于栈式架构的特点7.2、基于寄存器架构的特点 8、JVM的生命周…

React.FC详细说明以及案例

React.FC是React中用于定义函数式组件的一种类型。它是React.FunctionComponent的缩写&#xff0c;表示一个接收props作为输入并返回JSX元素的函数组件。React.FC提供了一种在TypeScript中使用的方式&#xff0c;允许我们为组件提供props的类型定义&#xff0c;并且可以利用Typ…

Unity3D 兰伯特漫反射光照模型详解

前言 Unity3D 提供了丰富的功能和工具&#xff0c;让开发者可以轻松创建出高质量的游戏。其中&#xff0c;光照模型是游戏中非常重要的一部分&#xff0c;它可以让游戏场景看起来更加真实和生动。在 Unity3D 中&#xff0c;我们可以使用不同的光照模型来实现不同的效果&#x…

网络基本类型

机器之间的通信是一个复杂的过程&#xff0c;它体现了大问题的复杂性。本章主要从“模型和结构”的计算思维概念&#xff0c;介绍网络通信的方法&#xff1b;并且用“安全”的概念&#xff0c;介绍网络攻击的防护方法&#xff0c;以及信息的加密和解密。 ▶1.互联网的发展 19…

嵌入式驱动学习第一周——定时器与延时函数

前言 这篇博客一起学习定时器&#xff0c;定时器是最常用到的功能之一&#xff0c;其最大的作用之一就是提供了延时函数。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&…

刷题第3天(基础理论):链表基础理论

1.链表定义&#xff1a;链表是一种通过指针串联在一起的线性结构。每个节点由两部分组成&#xff0c;一个是数据域&#xff0c;一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个节点的指针域指向null&#xff08;空指针的意思&#xff09; …

cRIO9040中NI9871模块的测试

硬件准备 CompactRIO9040NI9871直流电源&#xff08;可调&#xff09;网线RJ50转DB9线鸣志STF03-R驱动器和步进电机 软件安装 参考&#xff1a;cRIO9040中NI9381模块的测试 此外&#xff0c;需安装NI-Serial 9870和9871扫描引擎支持 打开NI Measurement&#xff06;Automa…

Docke相关命令总结

docker systemctl 相关 commanddetailsudo systemctl start docker启动dockersudo systemctl stop docker停止dockersudo systemctl restart docker重启dockersudo systemctl status docker查看docker状态 镜像相关 commanddetaildocker search 镜像名称搜索镜像docker pull …

多线程爬虫基础代码

#导入线程模块 import threading def coding(): #定义 coding 函数&#xff0c;用于打印字符串 "aaa" 十次for i in range(10):print("aaa")def ac(): #定义 ac 函数&#xff0c;用于打印字符串 "bbbb" 十次&a…

jetson nano——编译安装opencv-python==4.3.0.38

目录 1.下载源码&#xff0c;我提供的链接如下&#xff1a;2.解压文件3.安装依赖scikit4.安装opencv-python5.查看opencv-python版本 系统&#xff1a;jetson-nano-jp451-sd-card-image ubuntu 18.04 1.下载源码&#xff0c;我提供的链接如下&#xff1a; 链接&#xff1a;http…

网络:IPv6

1、由于IPv4地址资源枯竭&#xff0c;所以产生了IPV6。 版本长度地址数量IPv432 bit4 294 967 296IPv6128 bit340 282 366 920 938 463 374 607 431 768 211 456 2、IPv6的基本报头在IPv4报头基础上&#xff0c;增加了流标签域&#xff0c;去除了一些冗余字段&#xff0c;使报…

RabbitMQ常用命令笔记

Ubuntu 安装 sudo apt install rabbitmq-server查看状态 sudo rabbitmqctl status启动可视化插件 sudo rabbitmq-plugins enable rabbitmq_management查看可视化端口 sudo rabbitmqctl status添加用户名密码 sudo rabbitmqctl add_user 用户名 密码设置管理员权限 sudo r…

docker (十二)-私有仓库

docker registry 我们可以使用docker push将自己的image推送到docker hub中进行共享&#xff0c;但是在实际工作中&#xff0c;很多公司的代码不能上传到公开的仓库中&#xff0c;因此我们可以创建自己的镜像仓库。 docker 官网提供了一个docker registry的私有仓库项目&#…

Zookeeper基础入门-2【ZooKeeper 分布式锁案例】

Zookeeper基础入门-2【ZooKeeper 分布式锁案例】 四、ZooKeeper-IDEA环境搭建4.1.环境搭建4.1.1.创建maven工程&#xff1a;zookeeper4.1.2.在pom文件添加依赖4.1.3.在项目的src/main/resources 目录下&#xff0c;新建文件为“log4j.properties”4.1.4.创建包名com.orange.zk …