Spring的代理模式
目录
1、什么是代理模式?
2、为什么要用代理模式?
3、有哪几种代理模式?
4、静态代理
5、动态代理
(1)Proxy动态代理
(2)Enhancer动态代理
(3)dbUtil和动态代理的融合
1、什么是代理模式?
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
通俗的来讲代理模式就是我们生活中常见的中介。举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介。公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择。自己喜欢的车,然后付钱就可以了。
2、为什么要用代理模式?
中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。
3、有哪几种代理模式?
我们有多种不同的方式来实现代理。如果按照代理创建的时期来进行分类的话可以分为两种:
静态代理:
- 静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。
- 在程序员运行之前,代理类.class文件就已经被创建了。
动态代理:
动态代理是在程序运行时通过反射机制动态创建的。
动态代理类分为基于接口的动态代理(jdk自带)和基于子类的动态代理(第三方)。
4、静态代理
举一个例子,比如潘金莲对西门庆有意思,呢就会对西门庆抛媚眼,但是潘金莲怎么联系到西门庆呢?这时候就需要王婆来找到西门庆,完成潘金莲的抛媚眼操作。
首先定义一个女生接口,用来定义方法:
public interface IWonman {public void makeEyeWithMan();
}
再将定义潘金莲实现类,继承自女生,重新里面抛媚眼的方法:
public class PanJinLianImp implements IWonman{@Overridepublic void makeEyeWithMan() {System.out.println("回眸一笑,抛个媚眼~");}
}
再创建王婆的实体类,继承自女生接口,声明一个接口对象。用这个对象来完成方法的调用,相当于中介传播。
//代理
public class WangPoImp implements IWonman{//被代理对象IWonman obj;public WangPoImp(IWonman obj) {this.obj = obj;}@Overridepublic void makeEyeWithMan() {System.out.println("镇一壶酒,搞搞气氛~");obj.makeEyeWithMan();}
}
在西门庆中创建潘金莲对象和王婆对象,用王婆对象调用潘金莲对象的方法传入西门庆。
public class XiMenQingTest {public static void main(String[] args) {//1.创建被代理对象IWonman pan = new PanJinLianImp();//2.创建代理IWonman wang = new WangPoImp(pan);wang.makeEyeWithMan();}
}
这就是静态代理,每一次增加业务都要在代理中更新方法,稍微有点麻烦。
5、动态代理
(1)Proxy动态代理
动态代理跟静态代理的区别就是,静态代理需要重新写一个代理类来完成代理,而动态代理在测试类中运行时创建代理对象,并在这些代理对象的方法调用前后插入自定义的处理逻辑。
比如说我现在有个歌手类还有个杨坤实现类,杨坤继承自歌手,呢么想要让杨坤做歌手的一些行为的时候肯定不能直接和杨坤谈,要和经纪人谈。
ISinger接口:
public interface ISinger {public void sing();public int dance(int num);
}
YangKunImp实现类(继承自歌手接口,实现了里面的抽象方法):
public class YangKunImp implements ISinger{@Overridepublic void sing() {System.out.println("===空城===");}@Overridepublic int dance(int num) {System.out.println("===跳舞===");return 0;}
}
接下来在测试类中,我要创建一个经纪人来当代理对象,杨坤是被代理对象。
// 1.创建被代理对象
ISinger yang = new YangKunImp();
创建被代理对象杨坤。
// 2.创建代理对象// 创建了一个代理对象// yang.getClass().getInterfaces():获取被代理对象实现的所有接口。ISinger jingJiRen = (ISinger) Proxy.newProxyInstance(yang.getClass().getClassLoader(), yang.getClass().getInterfaces(), new InvocationHandler() {// invoke拦截方法调用@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("===做个自我介绍===");// 通过反射调用了 yang 对象的对应方法Object obj = method.invoke(yang,args);return obj;}});
创建代理对象经纪人,Proxy.newProxyInstance 是 Java 的 Proxy 类提供的一个静态方法,用于创建代理对象,里面要传三个参数,分别为:
yang.getClass().getClassLoader() 获取 yang 对象的类加载器,这个加载器用于加载代理类。
yang.getClass().getInterfaces() 获取 yang 对象实现的接口列表。这些接口会被代理对象实现。
new InvocationHandler() 是代理对象的核心部分,InvocationHandler 是一个接口,它的 invoke 方法会在代理对象的方法被调用时被执行。invoke是拦截方法调用,并允许你在调用目标对象的方法之前或之后添加额外的行为。反射调用了 yang 对象的对应方法,args是对应方法传进来的参数。
jingJiRen.sing();
最后调用了代理对象 jingJiRen 的 sing 方法。当 jingJiRen.sing() 被调用时,实际上是调用了 InvocationHandler 中的 invoke 方法,这会打印“===做个自我介绍===”,然后再调用 yang 对象的 sing 方法。
(2)Enhancer动态代理
跟Proxy差不多的用法,使用了 CGLIB 库来创建动态代理对象:
public static void main(String[] args) {//1.创建被代理对象ISinger teng = new TengGeErImp();//2.创建代理对象ISinger jing = (ISinger) Enhancer.create(teng.getClass(), teng.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {Object object = method.invoke(teng,objects);return object;}});jing.sing();
(3)dbUtil和动态代理的融合
就是在dbUtil的基础上,用动态代理来代替service层对dao层的一些业务请求。
首先就是定义一个工厂类,可以生成注入动态代理的对象:
public class ProxyBeanFactory {// 1.被代理对象IAccountService toProxyService;public void setToProxyService(IAccountService toProxyService) {this.toProxyService = toProxyService;}// 装配事务工具类TransactionUtil transactionUtil;public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}
在这个工厂类中首先生成被代理对象IAccountService,也就是service业务逻辑层实现类对象,用于调用方法和对dao层的连接。其次生成一个事务管理工具类,包含了事务的开始、提交、回滚和关闭操作。
// 2.创建代理public IAccountService createProxy(){IAccountService proxy = (IAccountService) Proxy.newProxyInstance(toProxyService.getClass().getClassLoader(), toProxyService.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object o = null;try {transactionUtil.beginTx();o = method.invoke(toProxyService,args);transactionUtil.commitTx();} catch (Exception e) {e.printStackTrace();transactionUtil.rollbackTx();} finally {transactionUtil.closeTx();}return o;}});return proxy;}
紧接着是我们的创建代理,用invoke方法拦截并映射service层中的方法,调用到后再加入开始事务、提交事务、回滚事务等操作,确保对应一个连接connection。
service层实现类中的代码:
public class AccountServiceImp implements IAccountService {IAccountMapper mapper;public void setMapper(IAccountMapper mapper) {this.mapper = mapper;}@Overridepublic void transfer(String sourceName, String targetName, int money) {//1.查询数据Account sourceAccount = mapper.findByName(sourceName);Account targetAccount = mapper.findByName(targetName);//2.转账sourceAccount.setAmoney(sourceAccount.getAmoney() - money);targetAccount.setAmoney(targetAccount.getAmoney() + money);//3.修改数据库mapper.updateById(sourceAccount);int a = 10/0;//模拟异常mapper.updateById(targetAccount);}@Overridepublic void save(Account account) {mapper.save(account);}@Overridepublic Account findByName(String name) {return mapper.findByName(name);}@Overridepublic List<Account> findAll() {return mapper.findAll();}@Overridepublic void updateById(Account account) {mapper.updateById(account);}@Overridepublic void deleteById(int id) {mapper.deleteById(id);}
}
因为controller将方法本来传递给service层,现在将方法传递给service的动态代理,所以在XML中将controller的bean里面注入service动态代理。
<!--注入代理service--><!--通过工厂方法 createProxy 来创建的代理对象。--><!--指定用于创建这个 bean 的工厂 bean,这里引用了后面定义的 factory bean。--><bean id="proxyService" class="com.apesource.service.AccountServiceImp" factory-bean="factory" factory-method="createProxy"></bean><bean id="factory" class="com.apesource.factory.ProxyBeanFactory"><property name="transactionUtil" ref="transactionUtil"></property><property name="toProxyService" ref="service"></property></bean><!--注入controller--><bean id="controller" class="com.apesource.controller.AccountControllerImp"><property name="service" ref="proxyService"></property></bean>
用已经定义好的工厂类(factory)里面的工厂方法(createProxy)来实例化一个AccountServiceImp的类。proxyService Bean 通过 ProxyBeanFactory 的 createProxy 方法创建,而不是直接通过 AccountServiceImp 类创建。再通过factory-bean方法指定用于创建这个 Bean 的工厂 Bean 的 ID,去注入工厂类中的成员变量transactionUtil和service实现类对象。再通过常见service对象去注入dao层的bean对象。
简单来说就是controller层调service的动态代理,动态代理调service,service调用dao。
相关文章:
Spring的代理模式
目录 1、什么是代理模式? 2、为什么要用代理模式? 3、有哪几种代理模式? 4、静态代理 5、动态代理 (1)Proxy动态代理 (2)Enhancer动态代理 (3)dbUtil和动态代理的…...
el-table合计放在标题上方且合并列以及渲染后端返回的数据
el-table二次封装的父组件中的属性 <y-table :table-data"tableData" :table-model"tableModel" :isShowSummary"true" :getSummaries"getSummaries"></y-table>el-table合计放在标题上方 <style lang"scss"…...
magic-api相关应用与配置
目录 项目启动 工具:IDEA 运行项目 关于配置 项目启动 工具:IDEA 新建——》项目——》导入——》运行 运行项目 http://localhost:9999/magic/web/index.htmlhttp://localhost:9999/magic/web/index.html 关于配置 配置多数据源 在线配置多数据…...
AI大模型赋能开发者|海云安创始人谢朝海受邀在ISC.AI 2024大会就“大模型在软件开发安全领域的应用”主题发表演讲
近日,ISC.AI 2024 第十二届互联网安全大会在北京国家会议中心盛大开幕。作为全球规格最高、规模最大、影响力最深远的安全峰会之一,本次大会以“打造安全大模型 引领安全行业革命”为主题,聚焦安全与AI两大领域,吸引了众多行业领袖…...
基于Kahn算法|动态线程池,支持扩展点并发执行|召回|过滤
背景 在《分布式领域扩展点设计稿》一文中,我们提到针对业务横向扩展点和纵向扩展点的编排能力。 那有这样的一种场景:针对于一次会话,同时会调很多外部服务,同时这些RPC服务会有多种直接或间接的关系,是否有更高效的…...
Bootstrap 4 表头固定,tbody滚动条
表格 <div class"row" style"background-color: #fff;overflow: auto;max-height: 500px;"> <table class"table table-striped table-bordered scrolltable text-nowrap"> <thead> …...
MYSQL知识点(持续更新)
数据库 文章目录 数据库Mysql基础篇数据库相关概念MYSQL启动数据库类型关系型数据库 SQL语法SQL通用语法SQL分类DDL - 数据库操作 Mysql基础篇 数据库相关概念 数据库、 存储数据的仓库,数据是组织的进行存储 数据库管理系统 操纵和管理数据库的大型软件 SQL语句…...
html+css网页设计 酷狗首页1个页面 (无js)
htmlcss网页设计 酷狗首页1个页面无js功能 页面还原度80% 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 …...
用户体验至上:9款软件界面设计工具分享
你知道如何选择正确的UI设计软件吗?您知道哪些界面设计软件需要设计美观的用户界面,以及带来良好用户体验的APP吗?根据APP界面的不同功能,制作软件界面的选择也会有所不同。但是,并非要非常精通所有的制作软件界面&…...
Lambda 表达式:解锁编程世界的魔法之门
引言 在这个技术日新月异的时代,编程语言不断进化以适应日益复杂的软件开发需求。其中,Lambda表达式作为一门现代编程语言的重要特性,已经成为了提升代码效率与可读性的关键工具。无论你是刚刚踏入编程领域的新手,还是已经在软件…...
【python】Pandas处理Excel表格用法分析与最佳实践
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
KL 散度(python+nlp)
python demo KL 散度(Kullback-Leibler divergence),也称为相对熵,是衡量两个概率分布之间差异的一种方式。KL 散度是非对称的,也就是说,P 相对于 Q 的 KL 散度通常不等于 Q 相对于 P 的 KL 散度。 一个简…...
四种推荐算法——Embedding+MLP、WideDeep、DeepFM、NeuralCF
一、EmbeddingMLP模型 EmbeddingMLP 主要是由 Embedding 部分和 MLP 部分这两部分组成,使用 Embedding 层是为了将类别型特征转换成 Embedding 向量,MLP 部分是通过多层神经网络拟合优化目标。——用于广告推荐。 Feature层即输入特征层,是模…...
鹏鼎控股:最新面试求职SHL逻辑测评笔试题库讲解及真题分享
鹏鼎控股(深圳)股份有限公司,成立于1999年4月29日,是一家专业从事印制电路板(PCB)设计、研发、制造与销售的企业。公司产品广泛应用于通讯、消费电子、汽车、服务器等多个领域,服务全球市场。鹏…...
【Git】git 不跟踪和gitignore区别
文章目录 不跟踪(Untracked):.gitignore 文件:总结 在 Git 中,不跟踪(untracked)和 .gitignore 文件有不同的作用和用途: 不跟踪(Untracked): 不…...
51单片机—智能垃圾桶(定时器)
一. 定时器 1. 简介 C51中的定时器和计数器是同一个硬件电路支持的,通过寄存器配置不同,就可以将他当做定时器或者计数器使用。 确切的说,定时器和计数器区别是致使他们背后的计数存储器加1的信号不同。当配置为定时器使用时,每…...
熵权法模型(评价类问题)
一. 概念 利用信息熵计算各个指标的权重,从而为多指标的评价类问题提供依据。 指标的变异程度越小,所反映的信息量也越少,所以其对应的权值也应该越低。 指标的变异程度(或称为变异性、波动性):描述了一…...
用uniapp 及socket.io做一个简单聊天app 踢人拉黑 7
在聊天群里,以及私聊时,可以点对方头象弹出踢跟拉黑,踢只是让对方退出聊天室。拉黑是记对方退出且不能再进入。 socket.io 中的踢人流程: 将用户从groupUsers 删除,表现在uniapp的界面,就是通知friends页&…...
springboot项目迁移到阿里云函数
注意:长耗时,高内存 的应用,定时任务 不适合迁移。spring-cloud的微服务项目暂不适合迁移。 一、根据模板创建项目 1.内网数据库连接配置 如果用到了rds或者阿里云上自建的mysql数据库 则配置 internetAccess: true vpcConfig:securityGrou…...
Java设计模式(桥接模式)
定义 将抽象部分与它的实现部分解耦,使得两者都能够独立变化。 角色 抽象类(Abstraction):定义抽象类,并包含一个对实现化对象的引用。 扩充抽象类(RefinedAbstraction):是抽象化角…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
