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

【SSM】Spring6(九.代理模式)

文章目录

  • 1.代理模式
  • 2. 静态代理
  • 3. 动态代理
    • 3.1 JDK动态代理
    • 3.2 CGLIB动态代理

1.代理模式

代理模式主要有两种:
静态代理模式
动态代理模式

2. 静态代理

有这样一个业务:订单的生成,修改,查看详情。实现如下

package com.sdnu.proxy.service;/*** 订单业务接口*/
public interface OrderService {void generate();void modify();void detail();
}
package com.sdnu.proxy.service;public class OrderServiceImpl implements OrderService{@Overridepublic void generate() {//模拟生成订单的耗时try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已生产");}@Overridepublic void modify() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已修改");}@Overridepublic void detail() {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("查看订单详情");}
}

测试

package com.sdnu.proxy.client;import com.sdnu.proxy.service.OrderService;
import com.sdnu.proxy.service.OrderServiceImpl;public class Test {public static void main(String[] args) {OrderService orderService = new OrderServiceImpl();orderService.generate();orderService.modify();orderService.detail();}
}

过了一段时间,有一个新的业务,我们需要统计订单的生成总时间,于是我们有如下的解决方案:

方案一:采用硬编码的方式,在每一个业务接口中的每一个业务方法直接写一个统计时间。
这种方案的缺点:(1)违背OCP原则
(2)代码没有得到复用

方案二:编写业务的子类,让子类继承原来的业务类,对每个业务方法进行重写。
这种方案的缺点:(1)虽然没有违背OCP原则,但是由于采用继承方式会导致代码的耦合度变高。
(2)代码没有得到复用

方案三:静态代理

代理对象

package com.sdnu.proxy.service;//代理对象
public class OrderServiceProxy implements OrderService{//将目标对象作为代理对象的一个属性,这种关系叫做关联关系,比继承关系耦合度低private OrderService target;public OrderServiceProxy(OrderService target) {this.target = target;}@Overridepublic void generate() {//代理方法long begin = System.currentTimeMillis();target.generate();long end = System.currentTimeMillis();System.out.println("耗时" + (end - begin) + "毫秒");}@Overridepublic void modify() {//代理方法long begin = System.currentTimeMillis();target.modify();long end = System.currentTimeMillis();System.out.println("耗时" + (end - begin) + "毫秒");}@Overridepublic void detail() {//代理方法long begin = System.currentTimeMillis();target.detail();long end = System.currentTimeMillis();System.out.println("耗时" + (end - begin) + "毫秒");}
}

测试

package com.sdnu.proxy.client;import com.sdnu.proxy.service.OrderService;
import com.sdnu.proxy.service.OrderServiceImpl;
import com.sdnu.proxy.service.OrderServiceProxy;public class Test {public static void main(String[] args) {OrderService orderService = new OrderServiceImpl();OrderServiceProxy orderServiceProxy = new OrderServiceProxy(orderService);orderServiceProxy.generate();orderServiceProxy.modify();orderServiceProxy.detail();}
}

这种静态代理符合OCP开闭原则,同时采用的是关联关系,所以程序的耦合度较低。
缺点:类爆炸问题。

3. 动态代理

在程序运行阶段,在内存中动态生成代理类,被称为动态代理,目的是为了减少代理类的数量。解决代码复用的问题。

常见的动态代理:

  • JDK动态代理
  • CGLIB动态代理
  • javassit动态代理

3.1 JDK动态代理

测试程序Test

package com.sdnu.proxy.client;import com.sdnu.proxy.service.OrderService;
import com.sdnu.proxy.service.OrderServiceImpl;
import com.sdnu.proxy.service.TimerInvocationHandler;import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {//创建目标对象OrderService target = new OrderServiceImpl();//创建代理对象OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new TimerInvocationHandler(target));//调用代理对象的代理方法orderServiceProxy.generate();orderServiceProxy.modify();orderServiceProxy.detail();}
}

代码OrderService orderServiceProxy = Proxy.newProxyInstance(类加载器, 接口类型, 调用处理器);做了两件事
● 第一件事:在内存中生成了代理类的字节码
● 第二件事:创建代理对象

参数:

类加载器:在内存中生成了字节码,要想执行这个字节码,也是需要先把这个字节码加载到内存当中的。所以要指定使用哪个类加载器加载。

接口类型:代理类和目标类实现相同的接口,所以要通过这个参数告诉JDK动态代理生成的类要实现哪些接口。

调用的处理器:这是一个JDK动态代理规定的接口,接口全名:java.lang.reflect.InvocationHandler。这是一个回调接口,也就是说调用这个接口中方法的程序已经写好了,就差这个接口的实现类了。


代理类
package com.sdnu.proxy.service;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class TimerInvocationHandler implements InvocationHandler {private Object target;public TimerInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//目标执行之前的增强long begin = System.currentTimeMillis();//反射机制调用目标对象上的目标方法Object retValue = method.invoke(target, args);//目标执行之后的增强long end = System.currentTimeMillis();System.out.println("耗时" + (end - begin) + "毫秒");return retValue;}
}

invoke方法有三个参数

  • Object proxy。代理对象。计这个参数只是为了后期的方便,如果想在invoke方法中使用代理对象的话,尽管通过这个参数来使用
  • Method method。目标方法。
  • Object[] args。目标方法调用时要传的参数。

3.2 CGLIB动态代理

CGLIB既可以代理接口,又可以代理类。底层采用继承的方式实现。所以被代理的目标类不能使用final修饰。

引入依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

相关文章:

【SSM】Spring6(九.代理模式)

文章目录1.代理模式2. 静态代理3. 动态代理3.1 JDK动态代理3.2 CGLIB动态代理1.代理模式 代理模式主要有两种&#xff1a; 静态代理模式 动态代理模式 2. 静态代理 有这样一个业务&#xff1a;订单的生成&#xff0c;修改&#xff0c;查看详情。实现如下 package com.sdnu.…...

【1017. 负二进制转换】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个整数 n &#xff0c;以二进制字符串的形式返回该整数的 负二进制&#xff08;base -2&#xff09;表示。 注意&#xff0c; 除非字符串就是 "0"&#xff0c;否则返回的字符串中不…...

C语言实现插入排序与希尔排序

目录 一&#xff0c;插入排序 插入排序C语言实现&#xff08;升序&#xff09; 1&#xff0c;将新元素插入到有序序列 2&#xff0c;循环的开始与终止 二&#xff0c;希尔排序 希尔排序C语言实现&#xff08;升序&#xff09; 1&#xff0c;单趟&#xff1a; 2&#x…...

第九章-DOM与CSS

style属性 文档中每个元素节点都有一个属性style。style属性包含着元素样式&#xff0c;查询这个属性将返回一个对象而不是一个简单的字符串。样式都存放在这个style对象的属性里。 var element getElementById("example") //查看颜色属性 element.style.color //…...

蓝桥杯真题练习

小蓝在玩一个寻宝游戏, 游戏在一条笔直的道路上进行, 道路被分成了 nn 个方格, 依次编号 1 至 nn, 每个方格上都有一个宝物, 宝物的分值是一个整数 (包括正数、负数和零), 当进入一个方格时即获得方格中宝物的分值。小蓝可 以获得的总分值是他从方格中获得的分值之和。 小蓝开始…...

插入排序的简单理解

详细描述 插入排序的基本思想是&#xff1a;将一个记录插入到已经排好序的有序表中&#xff0c;从而得到一个新的、记录数增 1 的有序表。 在其实现过程中使用双层循环&#xff0c;外层循环针对除了第一个元素之外的所有元素&#xff0c;内层循环针对当前元素前面的有序表进行…...

Springboot框架集成Websocket通信方式

Websocket实现了“服务器”主动向“客户端”发送数据,改变了以往通过轮询、长轮训、长连接等方式获取服务器端数据的方式。 一、Websocket有三种不同的用场景,单播、广播和组播; (一)、单播(Unicast) 单播是客户端与服务器之间的“一对一”的连接。是在一个单个的发送…...

将json数据分组

在工作中有时需要根据业务需要&#xff0c;将大量数据进行处理分成几个一组 // 例如要将下方数据进行处理 var stuCount [{"id": "1612321835288","libraryCode": "D","regionCode": "A","positionCode&qu…...

从零开始实现一个C++高性能服务器框架----Socket模块

此项目是根据sylar框架实现&#xff0c;是从零开始重写sylar&#xff0c;也是对sylar丰富与完善 项目地址&#xff1a;https://gitee.com/lzhiqiang1999/server-framework 简介 项目介绍&#xff1a;实现了一个基于协程的服务器框架&#xff0c;支持多线程、多协程协同调度&am…...

ld: library not found for -lcrt0.o

ld: library not found for -lcrt0.o 背景&#xff1a; Mac 系统编译的时候报错 语言&#xff1a;golang 原因&#xff1a; 代码使用了静态编译&#xff0c;-static。stack overflow 上说 This option will not work on Mac OS X unless all libraries (including libgcc.a…...

接口测试和功能测试的区别有哪些?说一些你不知道的知识

目录 接口测试和功能测试的区别 目的 测试范围 测试方法 重要性 ​编辑 举个例子 对于接口测试 对于功能测试 ​编辑 总结 接口测试和功能测试是软件测试中的两种常见测试类型&#xff0c;主要用于评估软件系统的质量。尽管这两种测试都是为了评估软件系统的性…...

深度学习实战——不同方式的模型部署(CNN、Yolo)

忆如完整项目/代码详见github&#xff1a;https://github.com/yiru1225&#xff08;转载标明出处 勿白嫖 star for projects thanks&#xff09; 目录 系列文章目录 一、实验综述 1.实验工具及及内容 2.实验数据 3.实验目标 4.实验步骤 二、ML/DL任务综述与模型部署知识…...

【论文阅读】GNN阅读笔记

A gentle introduction on gnn 前言 发表在distill的文章 图神经网络在应用上才刚刚开始 搭建了一个GNN playground 什么是图 图是表示实体之间的关系 可以分别表示成点向量、边向量、图向量 图可以分为有向图和无向图 数据是怎么表示成图 图片表示成图&#xff1a; …...

QT常用控件——QTreeWidget(树控件),QTableWidget控件

目录 ★先开个小灶,在此插句话:【有关Halcon与Qt联编变量转换】 QTreeWidget树控件 QTableWidget控件...

为什么学校购买小型数控机床而不是大型工业数控机床?

CNC 机器是计算机控制的设备&#xff0c;可以高精度和准确度地切割、雕刻、钻孔或雕刻各种材料。 它们广泛应用于制造、工程、设计和艺术行业。 CNC 机器具有不同的尺寸和功能&#xff0c;从小型台式机到大型工业机型。 人们可能想知道为什么学校会选择购买小型 CNC 机器而不是…...

【Go自学】一文搞懂Go append方法

我们先看一下append的源码 // The append built-in function appends elements to the end of a slice. If // it has sufficient capacity, the destination is resliced to accommodate the // new elements. If it does not, a new underlying array will be allocated. //…...

【压测】通过Jemeter进行压力测试(超详细)

文章目录背景一、前言二、关于JMeter三、准备工作四、创建测试4.1、创建线程组4.2、配置元件4.3、构造HTTP请求4.4、添加HTTP请求头4.5、添加断言4.6、添加察看结果树4.7、添加Summary Report4.8、测试计划创建完成五、执行测试计划总结背景 通过SpringCloudGateway整合Nacos进…...

C# | 上位机开发新手指南(七)加密算法

上位机开发新手指南&#xff08;七&#xff09;加密算法 文章目录上位机开发新手指南&#xff08;七&#xff09;加密算法前言加密算法的分类对称加密算法和非对称加密算法流加密算法和块加密算法分组密码和序列密码哈希函数和消息认证码对称加密与非对称对称加密优点缺点对称加…...

实验一 跨VLAN访问

目录 一、按照拓扑图配置VLAN&#xff0c;并实现跨VLAN间的访问。 二、实验环境 三、实验步骤 一、按照拓扑图配置VLAN&#xff0c;并实现跨VLAN间的访问。 1、配置好交换机的VLAN和各个终端的地址&#xff0c;实现各个VLAN内能连通。 2、开启两个交换机的VTY连接&#xff0…...

通信算法之130:软件无线电-接收机架构

1. 超外差式接收机 2.零中频接收机 3.数字中频接收机...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...