Java设计模式-结构型模式-代理模式

代理模式

  • 代理模式
    • 静态代理
    • 动态代理
      • JDK动态代理
      • CGlib动态代理

代理模式

创建一个代理对象来控制对原始对象的访问,可以用来扩展原始对象的功能,同时保护原始对象
一般使用代理模式的目的有两个:

  1. 保护目标对象
  2. 增强目标对象

代理模式有两种实现方案:静态代理 和 动态代理
在这里插入图片描述
下面以Dao层执行sql语句为例,讲述代理模式的 应用

静态代理

静态代理就是通过组合/继承的方式,代理类关联原始类,通过调用代理类的方法来实现 原始类的方法增强
这里有一个UserDaoImpl,作为原始类,提供一个模拟插入用户的接口

public interface UserDao {void insert();
}
/*****************************************************/public class UserDaoImpl implements UserDao{public void insert(){System.out.println("插入一个用户");}
}

创建一个静态代理类,StaticProxyUserDao,完成对userDao的增强

public class StaticProxyUserDao implements UserDao{private UserDao userDao;public StaticProxyUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void insert(){//事务开启...System.out.println("事务开启");userDao.insert();//方法增强...//事务提交...System.out.println("事务提交");}
}

测试代码如下,很容易理解,就不解释了

@Test
public void staticProxyTest(){//直接使用UserDao userDao = new UserDaoImpl();userDao.insert();System.out.println("---------------------------------------------------");//通过静态代理的方式,增强insert()方法StaticProxyUserDao staticProxyUserDao = new StaticProxyUserDao(userDao);staticProxyUserDao.insert();
}输出:
插入一个用户
---------------------------------------------------
事务开启
插入一个用户
事务提交

动态代理

通过静态代理的方式可以实现方法的增强,但对于每个增强的类,都需要再写一个代理类,这样显得代码比较臃肿,所以就有了动态代理,可以在程序执行过程中,动态的代理目标类。

动态代理有两种实现方式:JDK动态代理CGlib动态代理

JDK动态代理

JDK动态代理是Java标准库中提供的一种代理方式
JDK动态代理是依赖接口的。
实现方式:通过Proxy类中的 静态方法 newProxyInstance(…)实现

@Test
public void JdkProxyTest(){UserDao userDao = new UserDaoImpl();/** 参数1:指定一个类加载器* 参数2:指定接口 getInterfaces()* 参数3:指定对应的代理方法* */System.out.println();UserDao proxyUserDao = (UserDao)Proxy.newProxyInstance(UserDao.class.getClassLoader(), UserDaoImpl.class.getInterfaces(), (proxy, method, args) -> {System.out.println("事务开启");Object invoke = method.invoke(userDao,args);System.out.println("事务关闭");return invoke;});proxyUserDao.insert();
}

可以看出来,JDK动态代理的方法 必须在接口中有定义,所以,如果想要代理没有在接口中定义的方法,这就需要使用CGlib来实现

CGlib动态代理

CGlib 是基于 类继承实现的,通过继承目标类 来实现类的代理,所以目标类必须是可继承的
CGlib支持更细粒度的代理——针对某个方法进行代理
CGLIB是第三方提供的包,需要引入Jar包

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.1</version>
</dependency>

spring-core jar包里包含cglib ,所以使用spring框架的工程可以直接使用。
实现方式:通过Enhancer类实现,如下:

@Test
public void CGlibProxyTest(){// 创建Enhancer对象 类似于 Proxy类Enhancer enhancer = new Enhancer();// 设置父类的字节码对象 即需要代理的类enhancer.setSuperclass(UserDaoImpl.class);//设置回调函数,增强方法/*** o 代理对象,即生成的代理类的实例,这里是生成的代理对象,不是被代理对象* method 被代理方法的Method对象* args 方法调用时传递的参数数组* methodProxy 方法代理对象*/enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {System.out.println("事务开启");//这里注意使用的是 invokeSuper() 调用的是父类的接口Object invoke = methodProxy.invokeSuper(o,objects);System.out.println("事务关闭");return invoke;});// 生成代理对象UserDaoImpl proxy = (UserDaoImpl) enhancer.create();proxy.insert();
}

这里提一下注意的点:

JDK动态代理,依赖接口完成代理,没有实例对象,所以需要传入实例对象,
即 method.invoke(userDao,args); 中的userDao,所以在代理之前,需要先有个实例化的对象

而CGlib动态代理,依赖类继承实现,本身是知道代理对象的所有结构的,所以不需要传入实例对象,所以:
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
System.out.println(“事务开启”);
Object invoke = methodProxy.invokeSuper(o,objects);
System.out.println(“事务关闭”);
return invoke;
});
第一个参数是 代理对象,而不是被代理对象,调用方法使用的是 invokeSuper() 不是invoke(),调用的是父类的接口

关于CGlib和JDK代理的详细代理过程,可以看下这篇文章
https://blog.csdn.net/ren9436/article/details/125602288

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

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

相关文章

MATLAB | 官方举办的动图绘制大赛 | 第一周赛情回顾

嘿真的又是很久没见了&#xff0c;最近确实有点非常很特别小忙&#xff0c;今天带来一下MATHWORKS官方举办的迷你黑客大赛第三期(MATLAB Flipbook Mini Hack)的最新进展&#xff01;&#xff01;目前比赛已经刚好进行了一周&#xff0c;前两届都要求提交280个字符内的代码来生成…

JVM字符串常量池StringTable

目录 一、StringTable为什么要调整 二、String的基本特性 三、String的内存分配 四、字符串拼接操作 五、intern()方法 六、Stringtable的垃圾回收 七、G1中String去重操作 一、StringTable为什么要调整 jdk7之前&#xff0c;hotspot对于方法区的实现是永久代&#xff…

尝试使用php给pdf添加水印

在开发中增加pdf水印的功能是很常见的&#xff0c;经过实验发现这中间还是会有很多问题的。第一种模式&#xff0c;采用生成图片的方式把需要添加的内容保存成图片&#xff0c;再将图片加到pdf中间&#xff0c;这种方法略麻烦一些&#xff0c;不过可以解决中文乱码的问题&#…

互联网Java工程师面试题·微服务篇·第三弹

目录 34、什么是端到端微服务测试&#xff1f; 35、Container 在微服务中的用途是什么&#xff1f; 36、什么是微服务架构中的 DRY&#xff1f; 37、什么是消费者驱动的合同&#xff08;CDC&#xff09;&#xff1f; 38、Web&#xff0c;RESTful API 在微服务中的作用是什…

SpringCloud微服务:服务拆分

不同的数据库之间&#xff0c;如何共同调用&#xff1f;接下来讲讲两个数据库之间如何交互 1、微服务需要根据业务模块拆分&#xff0c;做到单一职责,不要重复开发相同业务 2、微服务可以将业务暴露为接口&#xff0c;供其它微服务使用 3、不同微服务都应该有自己独立的数据库…

(头哥)多表查询与子查询

目录 第1关&#xff1a;查询每个学生的选修的课程信息 第2关&#xff1a;查询选修了“数据结构”课程的学生名单 第3关&#xff1a;查询“数据结构”课程的学生成绩单 第4关&#xff1a;查询每门课程的选课人数 第5关&#xff1a;查询没有选课的学生信息 第6关&#xff1a…

【算法】新的开始(Kruskal算法,虚拟源点)

题目 发展采矿业当然首先得有矿井&#xff0c;小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井&#xff0c;但他似乎忘记了考虑矿井供电问题。 为了保证电力的供应&#xff0c;小 FF 想到了两种办法&#xff1a; 在矿井 i 上建立一个发电站&#xff0c;费用…

VB.NET三层之用户查询窗体

目录 前言: 过程: UI层代码展示: BLL层代码展示: DAL层代码展示: 查询用户效果图:​ 总结: 前言: 想要对用户进行查询&#xff0c;需要用到控件DataGrideView&#xff0c;通过代码的形式将数据库表中的数据显示在DataGrideview控件中&#xff0c;不用对DatGridView控件…

探索向量数据库 | 重新定义数据存储与分析

随着大模型带来的应用需求提升&#xff0c;最近以来多家海外知名向量数据库创业企业传出融资喜讯。 随着AI时代的到来&#xff0c;向量数据库市场空间巨大&#xff0c;目前处于从0-1阶段&#xff0c;预测到2030年&#xff0c;全球向量数据库市场规模有望达到500亿美元&#xff…

20.有效的括号(LeetCode)

思路&#xff1a;用栈的后进先出的特性&#xff0c;来完成题目的要求 因为C有库&#xff0c;可以直接用&#xff0c;而C语言没有&#xff0c;所以我们直接把写好的栈拷贝上来用。 首先&#xff0c;完成框架的搭建 其次&#xff0c;再实现循环内的部分。1.左括号入栈 2.右括…

数据分析实战 | KNN算法——病例自动诊断分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 九、模型调参 十、模型改进 十一、模型预测 一、数据及分析对象 CSV文件——“bc_data.csv” 数据集链接&#xff1a;https://dow…

HTML简单介绍

且视他人之疑目如盏盏鬼火&#xff0c;大胆地去你的夜路。 目录 1.网页 2.Web标准 3.HTML 3.1HTML结构 3.2HTML标签​编辑 4.标签介绍 4.1排版标签 4.2文本格式化标签 4.3媒体标签 4.3.1图片标签 4.3.2 音频标签 4.3.3视频标签 5.相对路径 6.链接标签 6.1target属…

车载通信与DDS标准解读系列(1):DDS-RPC

▎RPC & DDS-RPC RPC&#xff1a;Remote Procedure Call&#xff0c;远程过程调用。 远程过程调用是一种进程间通信&#xff0c;它允许计算机程序在另一个地址空间中执行子程序&#xff0c;就好像用别人的东西像用自己的一样&#xff0c;常用于分布式系统。 远程过程调用…

Rust编程中的线程间通信

1.消息传递 为了实现消息传递并发&#xff0c;Rust 标准库提供了一个 信道&#xff08;channel&#xff09;实现。信道是一个通用编程概念&#xff0c;表示数据从一个线程发送到另一个线程。 可以将编程中的信道想象为一个水流的渠道&#xff0c;比如河流或小溪。如果你将诸如…

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法

文章目录 0 代码仓库1 Dijkstra算法2 Dijkstra算法的实现2.1 设置距离数组2.2 找到当前路径的最小值 curdis&#xff0c;及对应的该顶点cur2.3 更新权重2.4 其他接口2.4.1 判断某个顶点的连通性2.4.2 求源点s到某个顶点的最短路径 3使用优先队列优化-Dijkstra算法3.1 设计内部类…

海上船舶交通事故VR模拟体验低成本高效率-深圳华锐视点

在海上运输行业&#xff0c;安全事故的防范和应对能力是企业安全教育的重中之重。针对这一问题&#xff0c;海上运输事故VR模拟逃生演练成为了一种创新且高效的教育手段。通过这种演练&#xff0c;企业能够在提升员工安全意识和技能方面获得多方面的帮助。 在VR船舶搜救演练中&…

Python高级语法----Python C扩展与性能优化

文章目录 1. 编写Python C扩展模块示例代码编译和运行运行结果2. 利用Cython优化性能示例代码编译和运行运行结果3. Python性能分析工具示例代码分析结果1. 编写Python C扩展模块 Python C扩展模块允许你将C语言代码集成到Python程序中,以提高性能。这对于计算密集型任务特别…

20.1 platform 设备驱动

一、Linux 驱动的分离与分层 1. 驱动的分隔和分离 现在有三个平台&#xff0c;A、B 和 C&#xff0c;这三个平台都有 MPU6050 设备。编写最简单的驱动框架如下图&#xff1a; 每个平台下都有一个主机驱动和设备驱动&#xff0c;主机驱动是必要的&#xff0c;因为不同的平台 I2…

设计模式JAVA

1 创建型 如何合理的创建对象&#xff1f; 1.1 单例模式 字面意思就是只能创建一个对象实例时使用。 例如&#xff0c;Windows中只能打开一个任务管理器&#xff0c;这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费&#xff0c;或出现各个窗口显示内容的不一致等…

软件开发流程

目录 1 软件开发流程 第1阶段&#xff1a;需求分析 第2阶段&#xff1a;设计 第3阶段&#xff1a;编码 第4阶段&#xff1a;测试 第5阶段&#xff1a;上线运维 2 角色分工 3 软件环境 1). 开发环境(development) 2). 测试环境(testing) 3). 生产环境(production) &a…