动态代理初步了解
准备案例
需求
模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。
分析与实现
定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。
/**模拟用户业务功能*/
public interface UserService {String login(String loginName , String passWord) ;void selectUsers();boolean deleteUsers();void updateUsers();
}
定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。
public class UserServiceImpl implements UserService{@Overridepublic String login(String loginName, String passWord) {long startTimer = System .currentTimeMillis();try {Thread.sleep(1000);if("admin".equals(loginName) && "1234".equals(passWord)) {return "success";}return "登录名和密码可能有毛病";} catch (Exception e) {e.printStackTrace();return "error";}finally{long endTimer = System.currentTimeMillis();System.out.println("login方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");}}@Overridepublic void selectUsers() {long startTimer = System .currentTimeMillis();System.out.println("查询了100个用户数据!");try {Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}finally{long endTimer = System.currentTimeMillis();System.out.println("selectUsers方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");}}@Overridepublic boolean deleteUsers() {long startTimer = System .currentTimeMillis();try {System.out.println("删除100个用户数据!");Thread.sleep(500);return true;} catch (Exception e) {e.printStackTrace();return false;}finally{long endTimer = System.currentTimeMillis();System.out.println("deleteUsers方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");}}@Overridepublic void updateUsers() {long startTimer = System .currentTimeMillis();try {System.out.println("修改100个用户数据!");Thread.sleep(2500);} catch (Exception e) {e.printStackTrace();}finally{long endTimer = System.currentTimeMillis();System.out.println("updateUsers方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");}}
}
定义测试类,创建实现类对象,调用方法。
public class Test {public static void main(String[] args) {UserService userService = new UserServiceImpl();System.out.println(userService.login("admin", "1234"));System.out.println(userService.deleteUsers());userService.selectUsers();userService.updateUsers();}
}
提出问题
业务对象的的每个方法都要进行性能统计,存在大量重复的代码。
使用动态代理解决问题
动态代理
代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。
关键步骤
1.必须有接口,实现类要实现接口(代理通常是基于接口实现的)。
2.创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。
代理过程
当我们要对login方法进行耗时统计时,先进入代理对象,然后统计开始时间,接着真正执行登录方法,最后统计结束时间,如下图所示:
代码
接口不用变,修改实现类和测试类,增加一个代理工具类,如下:
public class UserServiceImpl implements UserService{@Overridepublic String login(String loginName, String passWord) {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}if("admin".equals(loginName) && "1234".equals(passWord)) {return "success";}return "登录名和密码可能有毛病";}@Overridepublic void selectUsers() {System.out.println("查询了100个用户数据!");try {Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}}@Overridepublic boolean deleteUsers() {try {System.out.println("删除100个用户数据!");Thread.sleep(500);return true;} catch (Exception e) {e.printStackTrace();return false;}}@Overridepublic void updateUsers() {try {System.out.println("修改100个用户数据!");Thread.sleep(2500);} catch (Exception e) {e.printStackTrace();}}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)参数一:类加载器,负责加载代理类到内存中使用。参数二:获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行代理参数三:代理的核心处理逻辑*/
public class ProxyUtil {/**生成业务对象的代理对象。* @param obj* @return*/public static <T> T getProxy(T obj) {// 返回了一个代理对象了return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 参数一:代理对象本身。一般不管// 参数二:正在被代理的方法// 参数三:被代理方法,应该传入的参数long startTimer = System .currentTimeMillis();// 马上触发方法的真正执行。(触发真正的业务功能)Object result = method.invoke(obj, args);long endTimer = System.currentTimeMillis();System.out.println(method.getName() + "方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");// 把业务功能方法执行的结果返回给调用者return result;}});}
}
public class Test {public static void main(String[] args) {// 1、把业务对象,直接做成一个代理对象返回,代理对象的类型也是 UserService类型UserService userService = ProxyUtil.getProxy(new UserServiceImpl());System.out.println(userService.login("admin", "1234"));System.out.println(userService.deleteUsers());userService.selectUsers();userService.updateUsers(); // 走代理}
}
动态代理的优点
非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。
可以为被代理对象的所有方法做代理。
可以在不改变方法源码的情况下,实现对方法功能的增强。
不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。
相关文章:

动态代理初步了解
准备案例 需求 模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。 分析与实现 定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,…...

QT国际化
引入 在代码里面写中文就很low,运行时多语言切换是客户端程序都应该具备的。 qt国际化其实就是qt中字符串的字符集编码的设置。当然这个设置不是简单的选择一下什么语言就好,这个需要编程人员来处理的。 通常对于非拉丁字符(主要指latin1字符…...

微信小程序button按钮去除边框去除背景色
button边框 去除button边框 在button上添加plain“true”在css中添加button.avatar-wrapper {background: none}用于去除button背景色在css中添加button.avatar-wrapper[plain]{ border:0 }用于去除button边框...

Neo4j深度学习
Neo4j的简介 Neo4j是用Java实现的开源NoSQL图数据库。从2003年开始开发,2007年正式发布第一版,其源码托管于GitHtb。Neo4j作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理、软件分析、组织和…...

【数据结构C/C++】链式存储与顺序存储结构栈
文章目录 链式存储结构顺序存储结构 下面这篇文章是我大二时候写的比较详细的实现过程,再这篇文章我也会再一次比较简单的再次简述一下链式与顺序存储结构的实现方式。 链式存储结构与顺序存储结构详解 这里我就不使用C再一次实现这两个栈了,有兴趣的也可…...

【数据库系统概论】数据定义之基本表的定义/创建、修改和删除
前言 🚩定义/创建基本表语法示例 修改基本表语法示例 删除基本表语法示例 感谢 💖 前言 🚩 SQL支持数据库系统的三级模式结构,其模式、外模式和内模式中的基本对象有表、视图和索引,因此,SQL的数据定义功能…...

面试算法22:链表中环的入口节点(1)
题目 如果一个链表中包含环,那么应该如何找出环的入口节点?从链表的头节点开始顺着next指针方向进入环的第1个节点为环的入口节点。 例如,在如图4.3所示的链表中,环的入口节点是节点3。 分析 第1步:确认是否包含环…...

蓝桥杯---第二讲---二分与前缀和
文章目录 前言Ⅰ. 数的范围0x00 算法思路0x00 代码书写 Ⅱ. 数的三次方根0x00 算法思路0x01代码书写 Ⅲ. 前缀和0x00 算法思路0x01 代码书写 Ⅳ. 子矩阵的和0x00 算法思路0x01 代码书写 Ⅴ. 机器人跳跃问题0x00 算法思路0x01 代码书写 Ⅵ. 四平方和0x00 算法思路0x01 代码书写 …...

d3dx9_39.dll如何修复?最新修复d3dx9_39.dll方法分享
大家好!今天我要和大家分享的主题是“d3dx9_39.dll丢失的修复方法”。我们都知道,在使用电脑的过程中,经常会遇到各种问题,而其中最常见的就是文件丢失。d3dx9_39.dll就是其中一个常见的丢失文件。那么,如何修复这个丢…...

阿里云轻量应用服务器月流量限制说明(部分套餐不限流量)
阿里云轻量应用服务器部分套餐限制月流量,轻量应用服务器按照套餐售卖,有的套餐限制月流量,有的不限制流量。像阿里云轻量2核2G3M带宽轻量服务器一年108元和轻量2核4G4M带宽一年297.98元12个月,这两款是不限制月流量的。阿里云百科…...

项目设计:YOLOv5目标检测+机构光相机(intel d455和d435i)测距
1.介绍 1.1 Intel D455 Intel D455 是一款基于结构光(Structured Light)技术的深度相机。 与ToF相机不同,结构光相机使用另一种方法来获取物体的深度信息。它通过投射可视光谱中的红外结构光图案,然后从被拍摄物体表面反射回来…...

WPF中DataContext的绑定技巧
先看效果: 上面的绑定值都是我们自定义的属性,有了以上的提示,那么我们可以轻松绑定字段,再也不用担心错误了。附带源码。 目录 1.建立mvvm项目 2.cs后台使用DataContext绑定 3.xaml前台使用DataContext绑定 4.xaml前台使用Da…...

【Spring MVC研究】MVC原理:DispatcherServlet的初始化,初始化好等于MVC准备好
文章目录 1. EnableWebMVC 开启 MVC 功能2. 初始化自定义的 MVC 组件2.1. 初始化过程2.2. 如何分析复杂的 Spring 组件注册 3. 容器启动后会初始化 DispatcherServlet4. DispatcherServlet 初始化过程总结5. 资料参考 把DispatcherServlet 准备好意味着服务器已经可以处理请求了…...

Kafka的分布式架构与高可用性
导语 一开始我们就说过Kafka是一款开源的高吞吐、分布式的消息队列系统,那么今天我们就来说下它的分布式架构和高可用性以及双/多中心部署。 Kafka 体系架构简介 以下是 Kafka 的软件架构,整个 Kafka 体系结构由 Producer、Consumer、Broker、ZooKeepe…...

Spring Cloud学习笔记【分布式请求链路跟踪-Sleuth】
文章目录 Spring Cloud Sleuth概述概述主要功能:Sleuth中的术语和相关概念官网 zipkin配置下载运行zipkin下载zipkin运行 demo配置服务提供者 lf-userpom.xmlapplication.ymlUserController 服务调用者 lf-authpom.xmlapplication.ymlAuthController 测试 Spring Cl…...

Java开发中的操作日志详解(InsCode AI 创作助手)
Java开发中的操作日志详解 一、操作日志的作用 故障排除和调试: 操作日志可以记录应用程序的各种活动,包括错误、异常、警告和信息性消息。这有助于开发人员快速定位和解决问题。性能分析: 通过记录关键操作和性能指标,操作日志…...

FutureTask和CompletableFuture的模拟使用
模拟了查询耗时操作,并使用FutureTask和CompletableFuture分别获取计算结果,统计执行时长 package org.alllearn.futurtask;import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import lombok.AllArgsConstructor; imp…...

Redis作为缓存,mysql的数据如何与redis进行同步?
Redis作为缓存,mysql的数据如何与redis进行同步? 一定要设置前提,先介绍业务背景 延时双删 双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致 读操作:缓存命中,直接返回;缓存未…...

申请免费 SSL 证书为您的小程序加密通信
在今天的网络环境中,数据安全和隐私保护变得尤为重要。无论是网站还是应用程序,为其提供安全的通信渠道都是至关重要的。对于小程序开发者来说,使用 SSL(Secure Sockets Layer)证书可以有效地保障用户数据的安全&#…...

Go 并发编程
并发编程 1.1 并发与并⾏ 并⾏与并发是两个不同的概念,普通解释: 并发:交替做不同事情的能⼒并⾏:同时做不同事情的能⼒ 如果站在程序员的⻆度去解释是这样的: 并发:不同的代码块交替执⾏并⾏…...

鱼眼相机去畸变(图像拉直/展开/矫正)算法及实战总结
本文介绍两种方法 1、经纬度矫正法 2、棋盘格矫正法 一、经纬度矫正法 1、算法说明 经纬度矫正法, 可以把鱼眼图想象成半个地球, 然后将地球展开成地图,经纬度矫正法主要是利用几何原理, 对图像进行展开矫正。 经过P点的入射光线…...

es6 数据类型
es6 数据类型 map 数据类型 >Map 对象保存键值对。 用途 : Object的key无法支持该数据时需要了解对象大小时 map 数据类型任何值(对象或者原始值) 都可以作为一个键。 Object 的键只能是字符串 let myMap new Map(); let myMap1 new Map(); var keyStrin…...

【postgresql】
看到group by 1,2 和 order by 1, 2。看不懂,google,搜到了Stack Overflow 上有回答 What does SQL clause “GROUP BY 1” mean? 大概意思就是,group by, order by 后面跟数字,指的是 selec…...

【C++】空间配置器 allocator:原理及底层解析
文章目录 空间配置器一级空间配置器二级空间配置器1. 内存池2. SGI-STL中二级空间配置器设计 - - 哈希桶3. 二级空间配置器的空间申请 空间配置器的默认选择空间配置器的在封装:添加了数据类型大小空间配置器对象的构造与析构 容器中的 allocator 空间配置器 提到空…...

微信小程序 movable-area 区域拖动动态组件演示
movable-area 组件在小程序中的作用是用于创建一个可移动的区域,可以在该区域内拖动视图或内容。这个组件常用于实现可拖动的容器或可滑动的列表等交互效果。 使用 movable-area 组件可以对其内部的 movable-view 组件进行拖动操作,可以通过设置不同的属…...

隔离上网,安全上网
SDC沙盒数据防泄密系统(安全上网,隔离上网) •深信达SDC沙盒数据防泄密系统,是专门针对敏感数据进行防泄密保护的系统,根据隔离上网和安全上网的原则实现数据的代码级保护,不会影响工作效率,不…...

NOSQL Redis 数据持久化 RDB、AOF(二) 恢复
redis 执行flushall 或 flushdb 也会产生dump.rdb文件,但里面是空的。 注意:千万执行,不然rdb文件会被覆盖的。 dump.rdb 文件如何恢复数据 讲备份文件 dump.rdb 移动到redis安装目录并启动服务即可。 dump.rdb 自动触发 和手动触发 自…...

UDP通信
UDP通信 #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); - 参数:- sockfd : 通信的fd- buf : 要发送的数据- len : 发送…...

Bootstrap对溢出内容的两种处理:滚动条和隐藏两种方式
Bootstrap中定义了以下两个类来处理内容溢出的情况: 类overflow-auto:在固定宽度和高度的元素上,如果内容溢出了元素,将生成一个垂直滚动条,通过滚动条可以查看溢出的内容。 类overflow-hidden:在固定宽度和高度的元素…...

elasticsearch基本语法
这里写自定义目录标题 elasticsearch简介基本语法索引创建索引修改索引删除索引 查询简单查询精确查询条件查询范围查询:聚合查询:排序和分页: 参考文献: elasticsearch简介 Elasticsearch 是一个开源的分布式搜索和分析引擎&…...