对代理模式的理解

目录

  • 一、前言
  • 二、案例
    • 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的理解

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

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

相关文章

Ceph学习 - 1.存储知识

文章目录 1.存储基础1.1 基础知识1.1.1 存储基础1.1.2 存储使用 1.2 文件系统1.2.1 简介1.2.2 数据存储1.2.3 存储应用的基本方式1.2.4 文件存储 1.3 小结 1.存储基础 学习目标:这一节,我们从基础知识、文件系统、小节三个方面来学习。 1.1 基础知识 1.…

一种有效的隐私保护联邦学习方法-文章翻译

一种有效的隐私保护联邦学习方法 摘要 联邦学习已成为协作学习和隐私保护学习的一种很有前途的方法。联合学习过程中的参和者通过交换模型参数而不是实际的训练数据(他们可能希望保持私有)来合作训练模型。然而,参数交互和生成的模型仍然可能会披露有关所用训练数据的信息…

2024HW-->Wireshark攻击流量分析

在HW中,最离不开的,肯定是看监控了,那么就要去了解一些wireshark的基础用法以及攻击的流量!!!! 1.Wireshark的基本用法 比如人家面试官给你一段流量包,你要会用 1.分组详情 对于我…

Mac 配置 Aria2

文章目录 1. Aria2 安装1.1 安装 brew1.2 安装 Aria2 2. 配置 Aria22.1 创建配置文件 aria2.conf 和空对话文件 aria2.session2.2 编辑配置文件 aria2.conf 3. 开机启动设置3.1 创建用户启动文件3.2 管理自启动项 4. 配置 BT tracker 自动更新4.1 XIU2/TrackersListCollection …

总结:微信小程序中跨组件的通信、状态管理的方案

在微信小程序中实现跨组件通信和状态管理,有以下几种主要方案: 事件机制 通过事件机制可以实现父子组件、兄弟组件的通信。 示例: 父组件向子组件传递数据: 父组件: <child binddata"handleChildData" /> 子组件: Component({..., methods: { handleChildData(…

[leetcode] 25. K 个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

【智能排班系统】雪花算法生成分布式ID

文章目录 雪花算法介绍起源与命名基本原理与结构优势与特点应用场景 代码实现代码结构自定义机器标识RandomWorkIdChooseLocalRedisWorkIdChooselua脚本 实体类SnowflakeIdInfoWorkCenterInfo 雪花算法类配置类雪花算法工具类 说明 雪花算法介绍 在复杂而庞大的分布式系统中&a…

【Frida】【Android】 工具篇:ProxyPin抓包详解

&#x1f6eb; 系列文章导航 【Frida】【Android】01_手把手教你环境搭建 https://blog.csdn.net/kinghzking/article/details/136986950【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446【Frida】【Android】03_RPC https://bl…

【漏洞复现】某科技X2Modbus网关多个漏洞

漏洞描述 最近某科技X2Modbus网关出了一个GetUser的信息泄露的漏洞,但是经过审计发现该系统80%以上的接口均是未授权的,没有添加相应的鉴权机制,以下列举多个未授权接口以及获取相关敏感信息的接口。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律…

解决element-plus table组件 fixed=“right“(left)浮动后横向滚动文字穿透的问题

BUG 版本&#xff1a;element-plus 2.6.1 浏览器&#xff1a;360极速浏览器22.1 (Chromium内核) 组件&#xff1a;el-table组件 问题&#xff1a;在头部/尾部浮动加上斑马条纹后&#xff0c;横向滚动存在文字穿透的问题。具体如图&#xff1a; 白色背景行的文字&#xff0c…

《Ubuntu20.04环境下的ROS进阶学习6》

一、手持激光雷达建图 在上次的学习中我们已经使用hector_Mapping在仿真环境下建图了&#xff0c;那么本节我们将拿出真实雷达做一次室内的建图。我们使用的是思岚的S2L激光雷达。 二、下载思岚的应用手册 首先我们根据自己的激光雷达类型去到思岚官网下载相应的ROS包&#xff…

成都源聚达:抖音小店押金收费标准

在数字浪潮中&#xff0c;抖音小店如星辰般熠熠生辉&#xff0c;吸引了无数商家和创业者。然而&#xff0c;想要在这片星海中畅游&#xff0c;首先得了解其押金的收费标准。正如古人言&#xff1a;“无规矩不成方圆”&#xff0c;明确规则是成功的关键一步。 抖音小店的押金制度…

CSS-属性

&#x1f4da;详见 W3scholl&#xff0c;本篇只做快速思维索引。 CSS 背景 用于定义元素的背景效果。 background-colorbackground-imagebackground-positionbackground-repeatbackground-attachment background-color background-color 属性指定元素的背景色。 h1 {back…

mysql的安装和部署

##官网下载mysql 我下载的是一个mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz 可以通过xshell 或者xftp传送 xshell则是先下载一个lrzsz 执行以下的命令 yum install lrzsz -y #安装好我下面有个一键安装的脚本 #!/bin/bash#解决软件的依赖关系 yum install cmake ncurses…

Redis 客户端

Redis 客户端 客户端-服务器结构 Redis 同 Mysql 一样&#xff0c;也是一个客户端-服务器结构的程序&#xff0c;结构如下图&#xff1a; 注&#xff1a;Redis 客户端和服务器可以在同一个主机上&#xff0c;也可以在不同主机上 Redis 客户端的多种形态 自带的命令行客户端&…

通过 Cookie、Redis共享Session 和 Spring 拦截器技术,实现对用户登录状态的持有和清理(三)

本篇内容对应 “2.4 生成验证码” 小节 和 “4.7 优化登陆模块”小节 视频链接 1 Kaptcha介绍 Kaotcga是一个生成验证码的工具。 你的网站验证码是什么&#xff1f; 在我们这个牛客论坛项目&#xff0c;验证码分为两部分 给用户看的是图片&#xff0c;用户根据图片上显示的…

RTX RTOS 操作实例分析之---线程(thread)

0 Preface/Foreword 1 线程&#xff08;thread&#xff09; 1.1 线程定义 1.1.1 USE_BASIC_THREADS&#xff08;宏定义&#xff09; 经过以上步骤&#xff08;makefile包含&#xff09;&#xff0c;USE_BASIC_THREADS在编译阶段被定义到相应的模块中。 1.1.2 定义线程ID变量…

Mysql中的 IFNULL 函数的详解

Mysql中的 IFNULL 函数的详解 概念 在mysql中IFNULL() 函数用于判断第一个表达式是否为 NULL&#xff0c;如果第一个值不为NULL就执行第一个值。第一个值为 NULL 则返回第二个参数的值。 语法 IFNULL(a, b)Demo 举例说明 创建表 create table student_one( sno varchar(20)…

Three.js阴影贴图

生成阴影贴图的步骤如下&#xff1a; 从光位置视点&#xff08;阴影相机&#xff09;创建深度图。从相机的角度进行屏幕渲染在每个像素点&#xff0c;将阴影相机的MVP矩阵计算出的深度值与深度图值进行比较如果深度图值较低&#xff0c;则说明该像素点存在阴影 &#xff0c;因…

【前端Vue】社交信息头条项目完整笔记第3篇:三、个人中心,TabBar 处理【附代码文档】

社交媒体-信息头条项目完整开发笔记完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;一、项目初始化使用 Vue CLI 创建项目,加入 Git 版本管理,调整初始目录结构,导入图标素材,引入 Vant 组件库,移动端 REM 适配。二、登录注册准备,实现基本登录功能,登录状…