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

对代理模式的理解

目录

  • 一、前言
  • 二、案例
    • 1 代码
    • 2 自定义代理类【静态代理】
      • 2.1 一个接口多个实现,到底注入哪个依赖呢?
        • 2.1.1 @Primary注解
        • 2.1.2 @Resource注解(指定name属性)
        • 2.1.3 @Qualifier注解
      • 2.2 面向接口编程
      • 2.3 如果没接口咋办呢?
        • 2.3.1 示例
        • 2.3.2 继承
    • 3 动态代理

一、前言

  • 在【对AOP的理解】中,提到过代理模式。
  • 本篇文章进一步谈谈我对代理模式的理解。

二、案例

1 代码

@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@PostMapping("/login")public UserVO login(@RequestBody LoginRequest loginRequest) {UserDO userDO = userService.login(loginRequest.getUsername(), loginRequest.getPassword());return UserVO.builder().username(userDO.getUsername()).password(userDO.getPassword()).build();}
}public interface UserService {UserDO login(String username, String password);
}@Service
public class UserServiceImpl implements UserService {@Resourceprivate LoginProcess loginProcess;@Overridepublic UserDO login(String username, String password) {return loginProcess.login(username, password);}
}@Component
public class LoginProcess {public UserDO login(String username, String password) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return new UserDO().setUsername("forrest").setPassword("123456");}
}
  • 我们想知道“登录”过程耗费的时间,即loginProcess.login(username, password);耗费的时间。
  • 我们希望通过自定义代理类来实现。

2 自定义代理类【静态代理】

@Slf4j
@Service
public class UserProxyServiceImpl implements UserService {@Resourceprivate UserServiceImpl userServiceImpl;@Overridepublic UserDO login(String username, String password) {long startTimestamp = System.currentTimeMillis();UserDO userDO = userServiceImpl.login(username, password);log.info("login cost {} ms", System.currentTimeMillis() - startTimestamp);return userDO;}
}
  • 如果这么写,很显然,启动时会报错:No qualifying bean of type 'structure.proxy.example3.service.UserService' available: expected single matching bean but found 2: userProxyServiceImpl,userServiceImpl
@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;...
}
  • UserService是接口,有两个实现类,Spring不知道到底要注入哪个bean,因此报错了。

2.1 一个接口多个实现,到底注入哪个依赖呢?

  • 在Spring框架中,当存在多个相同类型的bean时,可以通过三种主要方式来指定注入哪一个bean:使用@Primary注解@Resouce注解(指定name属性)@Qualifier注解
2.1.1 @Primary注解
@Slf4j
@Service
@Primary
public class UserProxyServiceImpl implements UserService {...
}
2.1.2 @Resource注解(指定name属性)
@RestController
@RequestMapping("/user")
public class UserController {@Resource(name = "userProxyServiceImpl")private UserService userService;...
}
  • IDEA的友好提示:
    在这里插入图片描述
  • 妈妈再也不担心我注不对bean了:)
2.1.3 @Qualifier注解
  • @Resource(name = “userProxyServiceImpl”)相当于:
@Autowired
@Qualifier("userProxyServiceImpl")
@RestController
@RequestMapping("/user")
public class UserController {@Autowired@Qualifier("userProxyServiceImpl")private UserService userService;...
}
  • 同样,IDEA提供了友好的提示:
    在这里插入图片描述

2.2 面向接口编程

  • 我们通过改变使用的bean:从UserServiceImpl换成了UserProxyServiceImpl,就新增了一些逻辑,例如,记录“登录”消耗的时间。
  • 对调用者完全是无感的。
    • 这就是通过接口来解耦了调用方和实现方:调用方–接口–实现方。

2.3 如果没接口咋办呢?

2.3.1 示例
@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserServiceImpl userService;@PostMapping("/login")public UserVO login(@RequestBody LoginRequest loginRequest) {UserDO userDO = userService.login(loginRequest.getUsername(), loginRequest.getPassword());return UserVO.builder().username(userDO.getUsername()).password(userDO.getPassword()).build();}
}@Service
public class UserServiceImpl {@Resourceprivate LoginProcess loginProcess;public UserDO login(String username, String password) {return loginProcess.login(username, password);}
}
2.3.2 继承
@RestController
@RequestMapping("/user")
public class UserController {
//    @Resource
//    private UserServiceImpl userService;@Resourceprivate UserProxyServiceImpl userService;...
}@Slf4j
@Service
public class UserProxyServiceImpl extends UserServiceImpl {@Resourceprivate UserServiceImpl userServiceImpl;@Overridepublic UserDO login(String username, String password) {long startTimestamp = System.currentTimeMillis();UserDO userDO = userServiceImpl.login(username, password);log.info("login cost {} ms", System.currentTimeMillis() - startTimestamp);return userDO;}
}
  • 很显然,所有用到UserServiceImpl的地方,都要换成UserProxyServiceImpl。麻烦啊!
  • 因此,如果依赖的实现方可能变化,一定要面向接口编程啊!
    • 如果第三方没提供接口,也要自定义一个接口来解耦调用方和实现方!

3 动态代理

  • 详见:对AOP的理解

相关文章:

对代理模式的理解

目录 一、前言二、案例1 代码2 自定义代理类【静态代理】2.1 一个接口多个实现,到底注入哪个依赖呢?2.1.1 Primary注解2.1.2 Resource注解(指定name属性)2.1.3 Qualifier注解 2.2 面向接口编程2.3 如果没接口咋办呢?2.…...

#QT项目实战(天气预报)

1.IDE:QTCreator 2.实验: 3.记录: (1)调用API的Url a.调用API获取IP whois.pconline.com.cn/ipJson.jsp?iphttp://whois.pconline.com.cn/ipJson.jsp?ip if(window.IPCallBack) {IPCallBack({"ip":&quo…...

数据挖掘|关联分析与Apriori算法详解

数据挖掘|关联分析与Apriori算法 1. 关联分析2. 关联规则相关概念2.1 项目2.2 事务2.3 项目集2.4 频繁项目集2.5 支持度2.6 置信度2.7 提升度2.8 强关联规则2.9 关联规则的分类 3. Apriori算法3.1 Apriori算法的Python实现3.2 基于mlxtend库的Apriori算法的Python实现 1. 关联分…...

ChatGPT Excel 大师

原文:ChatGPT Excel Mastery 译者:飞龙 协议:CC BY-NC-SA 4.0 序言 欢迎来到 Excel 掌握的变革之旅,在这里,尖端技术和永恒专业知识在“ChatGPT Excel 掌握:释放专家技巧和窍门的力量”中融合。在当今快节…...

C 语言中的 end, _end 符号

使用 man 3 end 可以看到相关符号的解释 这些符号不是在 C 语言文件和头文件中定义的,它们是 ld 在链接所有 .o 文件的时候自己添加的。 end 和 _end 的地址,就是最终程序的堆的起始地址 要打印它们的话,一个样例程序在下面: …...

绿联 安装PDF工具

这是一个强大的本地托管的基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分、合并、转换、重组、添加图像、旋转、压缩等。这个本地托管的 Web 应用程序最初是 100% ChatGPT 制作的应用程序,现已发展…...

备战蓝桥杯---数论相关问题

目录 一、最大公约数和最小公倍数 二、素数判断 三、同余 四、唯一分解定理 五、约数个数定理 六、约数和定理 五、快速幂 六、费马小定理 七、逆元 一、最大公约数和最小公倍数 文章链接:最大公约数和最小公倍数 二、素数判断 文章链接:在J…...

苹果手表Apple Watch录了两个半小时的录音,却只能播放4秒,同步到手机也一样,还能修复好吗?

好多人遇到这个情况,用苹果手表Apple Watch录音,有的录1个多小时,有的录了3、4小时,甚至更长时间,因为手表没电,忘记保存等原因造成录音损坏,都是只能播放4秒,同步到手机也一样&…...

RGB三通道和灰度值的理解

本文都是来自于chatGPT的回答!!! 目录 Q1:像素具有什么属性?Q2:图像的色彩是怎么实现的?Q3:灰度值和颜色值是一个概念吗?Q4:是不是像素具有灰度值,也有三个颜色分量RGB?Q5:灰度图像是没有色彩的吗?Q6: 彩色图像是既具有灰度值也具有RGB三…...

ARM、X86、RISC-V三分天下

引入: 简单的介绍一下X86、ARM、RISC-V三种cpu架构的区别和应用场景。 目录 简单概念讲解 1. X86架构 2. ARM架构 3. RISC-V架构 应用场景 X86、ARM和RISC-V是三种不同的CPU架构,它们在设计理念、指令集和应用场景上有一些区别。 简单概念讲解 1. X…...

力控机器人原理及力控制实现

力控机器人原理及力控制实现 力控机器人是一种能够感知力量并具有实时控制能力的机器人系统。它们可以在与人类进行精准协作和合作时,将力传感技术(Force Sensing Technology)和控制算法(Control Algorithm)结合起来&a…...

最小生成树

最小生成树问题是指给定一个带权的无向图,删除一些边使得这个无向图变成一棵树,并且权值之和最小。 解决此类问题的方法主要有两种:Prim算法,Kruskal算法 Prim 算法 从一个点开始,逐步扩展,每次选择权值…...

二维动画制作软件 Animate 2024 for mac激活版

Animate 2024 for Mac是一款功能强大的二维动画制作软件,专为Mac用户打造。它提供了丰富的动画编辑功能,使用户能够轻松创建出生动逼真的动画作品。无论是短片、广告还是游戏等应用领域,Animate 2024都能发挥出出色的表现。 软件下载&#xf…...

相对论中关于光速不变理解的补充

近几个月在物理直播间聊爱因斯坦相对论,发现好多人在理解爱因斯坦相对论关于基本假设,普遍认为光速是不变的,质能方程 中光速的光速不变的,在这里我对这个假设需要做一个补充,他是基于质能方程将光速C 在真是光速变化曲…...

面试(04)————JavaWeb

1、网络通讯部分 1.1、 TCP 与 UDP 区别? 1.2、什么是 HTTP 协议? 1.3、TCP 的三次握手,为什么? 1.4、HTTP 中重定向和请求转发的区别? 1.5、 Get 和 Post 的区别? 2、cookie 和 session 的区别&am…...

Debian12 使用 nginx 与 php8.2 使用 Nextcloud

最近将小服务器升级了下系统,使用了 debian12 的版本,正好试试 nginx 和 php-fpm 这种方式运行 Nextcloud 这个私有云的配置。 一、基本系统及应用安装 系统:debian12 x86_64 位版本最小安装,安装后可根据自己需求安装一些工具&…...

Java设计模式:代理模式的静态和动态之分(八)

码到三十五 : 个人主页 心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 ! 在软件设计中,代理模式是一种常用的设计模式,它为我们提供了一种方式来控制对原始对象的访问。在Java中&a…...

【论文通读】AgentStudio: A Toolkit for Building General Virtual Agents

AgentStudio: A Toolkit for Building General Virtual Agents 前言AbstractMotivationFramework评估GUI GroudingReal-World Cross-Application Benchmark Suite Conclusion 前言 来自昆仑万维的一篇智能体环境数据大一统框架工作,对未来计算机智能体的发展具有指…...

wordvect嵌入和bert嵌入的区别

Word2Vec 嵌入和 BERT 嵌入之间有几个关键区别: 训练方式: Word2Vec:Word2Vec 是一个基于神经网络的词嵌入模型,它通过训练一个浅层的神经网络来学习单词的分布式表示。它有两种训练方式:连续词袋模型(CBOW…...

渗透测试练习题解析 5(CTF web)

1、[安洵杯 2019]easy_serialize_php 1 考点:PHP 反序列化逃逸 变量覆盖 【代码审计】 通过 GET 的方式获取参数 f 的值,传递给变量 function 定义一个过滤函数,过滤掉特定字符(用空字符替换) 下面的代码其实没什么用…...

PCA(Principal Component Analysis,主成分分析)

PCA(Principal Component Analysis,主成分分析)是一种在数据分析中广泛应用的统计方法,主要用于数据降维、可视化和去噪。以下是对PCA的发展史、工作原理以及理论基础的详细解释: Principal Component Analysis 一、PC…...

干货 | 探索CUTTag:从样本到文库,实验步步为营!

CUT&Tag(Cleavage Under Targets and Tagmentation)是一种新型DNA-蛋白互作研究技术,主要用于研究转录因子或组蛋白修饰在全基因组上的结合或分布位点。相比于传统的ChIP-seq技术,CUT&Tag反应在细胞内进行,创新…...

提质不增本,降本不降质

#公益巡讲# #质量万里行# 公开课、沙龙活动...

数据结构---顺序表实现

目录 1.顺序表 2.动态顺序表的实现 (4)顺序表初始化 (5)顺序表销毁 (6)顺序表的插入 a.尾插 b.头插 (7)顺序表的删除 a.尾删 b.头删 (8)指定位置之…...

python docx 添加动态表格

在Python中,使用python-docx库可以创建Word文档并添加动态表格。以下是一个简单的例子,演示如何创建一个包含动态内容的表格: from docx import Document# 创建一个Word文档 document Document()# 添加一个标题 document.add_heading(动态表…...

git配置多SSH

目的: 一台电脑可以让github、gitee等账号同时存在,让不同账号配置不同的密钥 第一步:创建不同平台的SSH公钥 执行命令: ssh-keygen -t rsa -C "对应仓库邮箱地址" -f ~/.ssh/id_rsa.github 如果执行上面的命令&…...

IDEA连接SqlServer数据库

目录 下载jar包 下载sqljdbc_12.6压缩包 解压 导入IDEA 新建文件夹 复制粘贴进JDBC文件夹并设为library 编写类及方法 代码 下载jar包 以sqljdbc_12.6为例 下载sqljdbc_12.6压缩包 最新地址:sqljdbc 官方最新地址 解压 解压即用 导入IDEA 新建文件夹 复制…...

LeetCode 378 有序矩阵中第K小的元素

题目信息 LeetoCode地址: . - 力扣(LeetCode) 题解内容大量转载于:. - 力扣(LeetCode) 题目理解 题意很直观,就是求二维矩阵中所有元素排序后第k小的数。 最小堆写法 该写法不再赘述,维护…...

Vue3(domdiff)最长递归子序列求解简易版(超简单)

Vue3(domdiff)最长递归子序列求解简易版 ⚠️ 关键词(每一个都需要理解)js 代码实现写完感想欢迎关注 ⚠️ 关键词(每一个都需要理解) 动态规划(O(N^2))(不提倡&#xf…...

LLaMA-Factory+qwen多轮对话微调

LLaMA-Factory地址:https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md qwen地址:https://huggingface.co/Qwen/Qwen-7B-Chat/tree/main 数据准备 数据样例 [ {"id": "x3959", "conversations": [{&qu…...

手机网站公司/域名注册需要哪些条件

如何获取光标下的文本?因此,如果我将鼠标悬停在它上面并且单词“hi”,我可以阅读它吗?我想我需要用QTextCursor.WordUnderCursor做一些事情,但我不确定是什么.有帮助吗? 这就是我现在正在努力解决的问题: textCursor text.cursor…...

wordpress uctheme/百度极速版客服人工在线咨询

我需要一些帮助来替换和添加自己的Header到DualCore风格。我试图联系风格的作者,但看起来他并不可用。HTML/CSS:如何在phpBB风格中添加自定义横幅正如你可以看到在登录链接下右上方有一个小标题,但我在替换它和添加自己的标题时遇到了一些困难…...

旅游景区网站建设方案文档/上海站群优化

相信很多人在学习Python的时候都想用Pycharm专业版来写Python代码!但是他要收费!到网上找了很多的方法,找到了一个比较靠谱的方法解决了这个问题:、 1、 首先到官网(https://www.jetbrains.com/pycharm/download/#se…...

亿网通官网/详细描述如何进行搜索引擎的优化

CentOS7中的python版本为python2.7.5,升级到最新版的python时需要注意两个问题 新版的python安装好后要修改python的系统默认指向问题升级到最新版python后yum报错的问题下面对新版的安装步骤进行说明。 一、下载并安装最新版python 1.下载并解压 # wget https://ww…...

域名注册好如何做网站/东莞精准网络营销推广

AX里没有繁体中文的标签,只有简体中文,License Code里也只有简体中文。虽然从小用的都是简体中文,所以期望大统一,香港台湾大陆大家都用简体中文,叫法也统一一下,就不用这么麻烦了,但是人家还想…...

建网站知乎/全网热搜关键词排行榜

第一种方法: 记得有一本书上介绍 说 0权限重启手机,原理是 在android 系统中,当显示一个toast,其实是将该toast挂载到窗体上, 而窗体又是系统的一个服务, 如果单位时间内不断地向窗体上挂载toast,就会不断的申请系统内…...