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

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Omit<T, K> 解释
  • 【电子数据取证】支持最新版微信、企业微信、钉钉等重点应用数据提取分析!
  • 网络安全知识讲解
  • C语言典型例题30
  • Vue 3 中,组件间传值有多种方式
  • 【知识】pytorch中的pinned memory和pageable memory
  • Android Fragment:详解,结合真实开发场景Navigation
  • Java开发笔记--通用基础数据校验的设计
  • 思科CCIE最新考证流程
  • 工业三防平板助力MES系统打造工厂移动式生产管理
  • 视频编辑与制作软件哪个好 会声会影视频制作教程 会声会影软件下载免费中文版
  • 结构开发笔记(二):solidworks软件(一):介绍、下载和安装过程
  • JVM内存模型笔记
  • Print 前端打印 (调用 windows 自带打印功能,打印指定 dom 元素内容)
  • 【机器学习算法基础】(基础机器学习课程)-11-k-means-笔记
  • Android Studio:GIT提交项目到远程仓库
  • C++11: atomic 头文件
  • iOS编译提示和导航提示
  • JAVA 学习IO流
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • Kibana配置logstash,报表一体化
  • Next.js之基础概念(二)
  • php中curl和soap方式请求服务超时问题
  • VUE es6技巧写法(持续更新中~~~)
  • Vue.js-Day01
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 从零开始在ubuntu上搭建node开发环境
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 记一次用 NodeJs 实现模拟登录的思路
  • 解决iview多表头动态更改列元素发生的错误
  • 坑!为什么View.startAnimation不起作用?
  • 区块链共识机制优缺点对比都是什么
  • zabbix3.2监控linux磁盘IO
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • !!java web学习笔记(一到五)
  • #100天计划# 2013年9月29日
  • #APPINVENTOR学习记录
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (libusb) usb口自动刷新
  • (STM32笔记)九、RCC时钟树与时钟 第二部分
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (十三)Maven插件解析运行机制
  • (算法)Game
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .NET Framework 3.5安装教程
  • .NET Micro Framework初体验
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .net wcf memory gates checking failed
  • .net生成的类,跨工程调用显示注释
  • .net知识和学习方法系列(二十一)CLR-枚举
  • @JsonFormat 和 @DateTimeFormat 的区别
  • @test注解_Spring 自定义注解你了解过吗?
  • [ C++ ] STL---string类的模拟实现
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798