当前位置: 首页 > 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.数字中频接收机...

C++编程大师之路:从入门到精通-C++基础入门

文章目录前言主要内容C基础入门初识C第一个C程序注释变量常量关键字标识符命名规则数据类型整型sizeof关键字实型&#xff08;浮点型&#xff09;字符型转义字符字符串型布尔类型 bool数据的输入运算符算术运算符赋值运算符比较运算符逻辑运算符程序流程结构选择结构if语句三目…...

如何在千万级数据中查询 10W 的数据并排序

前言 在开发中遇到一个业务诉求&#xff0c;需要在千万量级的底池数据中筛选出不超过 10W 的数据&#xff0c;并根据配置的权重规则进行排序、打散&#xff08;如同一个类目下的商品数据不能连续出现 3 次&#xff09;。 下面对该业务诉求的实现&#xff0c;设计思路和方案优…...

RocketMQ消息文件过期原理

文章目录 消费完后的消息去哪里了?什么时候清理物理消息文件?这样设计带来的好处跳过历史消息的处理所有的消费均是客户端发起Pull请求的,告诉消息的offset位置,broker去查询并返回。但是有一点需要非常明确的是,消息消费后,消息其实并没有物理地被清除,这是一个非常特殊…...

Docker容器理解

目录 目录 一&#xff1a;简单理解操作系统 操作系统&#xff1a; 内核&#xff1a; 内核空间和用户空间&#xff1a; 二&#xff1a;简单理解文件系统 1&#xff1a;什么是文件系统 2&#xff1a;什么是root文件系统 三&#xff1a;docker 1&#xff1a;docker镜像 2&…...

SpringBoot 整合knife4j

文章目录SpringBoot 整合knife4j引入knife4j注解案例knife4j增强功能接口添加作者资源屏蔽访问页面加权控制接口排序分组排序请求参数缓存过滤请求参数禁用调试禁用搜索框SpringBoot 整合knife4j Knife4j是一款基于Swagger 2的在线API文档框架 在Spring Boot中&#xff0c;使…...

73-归并排序练习-LeetCode148排序链表

题目 给你链表的头结点 head &#xff0c;请将其按升序排列并返回排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&#xff…...

Hystrix学习笔记

Hystrix 官方文档&#xff1a; https://github.com/Netflix/Hystrix/wiki 是什么 In a distributed environment, inevitably some of the many service dependencies will fail. Hystrix is a library that helps you control the interactions between these distributed …...

面向对象编程(基础)8:关键字:package、import

目录 8.1 package(包) 8.1.1 语法格式 说明&#xff1a; 8.1.2 包的作用 8.1.3 应用举例 举例2&#xff1a;MVC设计模式 8.1.4 JDK中主要的包介绍 8.2 import(导入) 8.2.1 语法格式 8.2.2 应用举例 8.2.3 注意事项 8.1 package(包) package&#xff0c;称为包&#x…...

【机器学习】P10 从头到尾实现一个线性回归案例

这里写自定义目录标题&#xff08;1&#xff09;导入数据&#xff08;2&#xff09;画出城市人口与利润图&#xff08;3&#xff09;计算损失值&#xff08;4&#xff09;计算梯度下降&#xff08;5&#xff09;开始训练&#xff08;6&#xff09;画出训练好的模型&#xff08;…...

【Java EE】-多线程编程(四) 死锁

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【JavaEE】 分享&#xff1a;2023.3.31号骑行的照片再发一次(狗头)。 主要内容&#xff1a;什么是死锁&#xff1f;不可重入可重入、死锁的三个典型情况&#xff1a;1、一个线程一…...