Java研学-代理模式

一 概述

1 分类

  静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。(代理类及对象要自行创建)
  动态代理:代理类是在程序运行期间由 JVM 通过反射等机制动态的生成的,不存在代理类的字节码文件,动态生成字节码对象,代理对象和真实对象的关系是在程序运行时期才确定的。(代理类及对象不需要自行创建)

2 动态代理实现方式

  真实类有接口使用 JDK 动态代理;
  真实类没实现接口使用 CGLIB 或 Javassist 组件。

二 静态代理

1 介绍

  静态代理是一种代理模式,其中代理对象在编译时就确定下来,而不是在运行时动态创建。静态代理由业务实现类、业务代理类两部分组成。业务实现类负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截、过滤、预处理。

  静态代理的优点是可以实现对目标方法的扩展,控制真实对象的访问权限,避免创建大对象,以及增强真实对象功能。业务类只需要关注业务逻辑本身,保证了业务类的重用性。把真实对象隐藏起来了,保护真实对象。

  缺点是如果一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。
在这里插入图片描述

2 导入依赖

  <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.8.RELEASE</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>

3 业务类

// 真实类与代理类需实现相同的接口
public interface EmployeeService {/*员工保存*/public int save(String username,String password);
}
// 真实类
public class EmployeeServiceImpl implements EmployeeService {@Overridepublic int save(String username, String password) {System.out.println("员工姓名:"+username+"密码:"+password);return 0;}
}

4 代理类

public class EmployeeServiceProxy implements EmployeeService {/*setter注入真实对象,增加事务操作*/private EmployeeServiceImpl employeeService;public void setEmployeeService(EmployeeServiceImpl employeeService) {this.employeeService = employeeService;}/*setter注入事务管理对象*/private TransactionManager transactionManager;public void setTransactionManager(TransactionManager transactionManager) {this.transactionManager = transactionManager;}/*执行真实对象的业务方法以及事务方法*/@Overridepublic int save(String username, String password) {try {/*开启事务*/transactionManager.begin();/*调用真实的业务方法*/employeeService.save(username,password);/*设置异常*/int num=10/0;/*提交事务*/transactionManager.commit();} catch (Exception e) {/*事务回滚*/transactionManager.rollback();e.printStackTrace();}return 0;}
}

5 事务类

public class TransactionManager {/*开启事务*/public void begin(){System.out.println("事务开启了.....");}/*提交事务*/public void commit(){System.out.println("事务提交了........");}/*回滚事务*/public void rollback(){System.out.println("事务回滚了.........");}
}

6 resources配置文件 – spring-core.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--事务管理对象--><bean id="transactionManager" class="cn.tj.tx.TransactionManager"></bean><!--代理对象 为代理对象注入2Bean--><bean id="employeeServiceProxy" class="cn.tj.proxy.EmployeeServiceProxy"><property name="transactionManager" ref="transactionManager"></property><property name="employeeService" ><bean class="cn.tj.service.impl.EmployeeServiceImpl"></bean></property></bean>
</beans>

7 测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-core.xml")
public class EmployeeServiceTest {// employeeServiceProxy是bean的id 要一致@Autowiredprivate EmployeeService employeeServiceProxy;@Testpublic void emp_save() {//调用代理对象的方法employeeServiceProxy.save("叶凡","19216875523");}
}

三 JDK 动态代理

1 API

① java.lang.reflect.Proxy
  Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

// 主要方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler hanlder)// 参数
loader :类加载器,一般传递真实对象的类加载器;
interfaces:代理类需要实现的接口;
handler:代理执行处理器,说人话就是生成代理对象帮你要做什么。
返回:创建的代理对象。// 作用
为指定类加载器、一组接口及调用处理器生成动态代理类实例。

② java.lang.reflect.InvocationHandler
  由代理类实例的调用处理程序实现的接口

// 主要方法
public Object invoke(Object proxy, Method method, Object[] args)// 参数
proxy :生成的代理对象;
method:当前调用的真实方法对象;
args :当前调用方法的实参。
返回:真实方法的返回结果。// 作用
负责集中处理动态代理类上的所有方法调用,让使用者自定义做什么事情,对原来方法增强(加什么功能)。

2 代理类 – TransactionInvocationhandler

// jdk动态代理执行器 实现 InvocationHandler 接口,实现 invoke 方法,实现增强操作
public class TransactionInvocationhandler implements InvocationHandler {/*注入真实对象:程序运行起来之后才会知道是什么对象*/private Object object;public void setObject(Object object) {this.object = object;}public Object getObject() {return object;}/*注入扩展对象:事务对象*/private TransactionManager transactionManager;public void setTransactionManager(TransactionManager transactionManager) {this.transactionManager = transactionManager;}/*将真实业务方法和扩展方法组合执行*/@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable {Object o=null;try {/*开启事务*/transactionManager.begin();/*执行真实对象的方法:反射调用类成员方法*/o= method.invoke(object,args);/*设置异常*/// int num=10/0;/*提交事务*/transactionManager.commit();} catch (Exception e) {e.printStackTrace();/*回滚事务*/transactionManager.rollback();}return o;}
}

3 配置文件 – spring-core.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--事务管理对象--><bean id="transactionManager" class="cn.tj.tx.TransactionManager"></bean><!--代理执行器对象--><bean id="transactionInvocationhandler" class="cn.tj.proxy.TransactionInvocationhandler"><property name="transactionManager" ref="transactionManager"></property><property name="object" ><bean class="cn.tj.service.impl.EmployeeServiceImpl"></bean></property></bean>
</beans>

4 真实类接口实现类与事务类不变

5 测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-core.xml")
public class EmployeeServiceTest {@Autowiredprivate TransactionInvocationhandler transactionInvocationhandler;@Testpublic void emp_save() {//创建代理对象 (静态方法) 返回值应为service 默认为Object 故强转EmployeeService employePproxy = (EmployeeService) Proxy.newProxyInstance(transactionInvocationhandler.getObject().getClass().getClassLoader(),//通过执行器对象获取到真实对象的类加载器transactionInvocationhandler.getObject().getClass().getInterfaces(),//通过执行器对象获取真实对象实现的接口transactionInvocationhandler);System.out.println(employePproxy);//调用代理对象的方法
//        employePproxy.save("李四","333333");}
}

四 CGLIB 动态代理

1 API

① org.springframework.cglib.proxy.Enhancer

  Enhancer是CGLIB中用于字节码增强的类,类似于JDK动态代理中的Proxy类。它能够代理普通Java类和接口,通过创建一个被代理类的子类来拦截所有的方法调用。Enhancer的主要方法包括setSuperclass设置代理类的父类,setCallback设置回调函数等。

② org.springframework.cglib.proxy.InvocationHandler

  类似 JDK 中 InvocationHandler,CGLIB 库中的一个接口,用于拦截目标对象的代理方法调用。当一个代理对象被调用时,会先调用该接口的实现类中的invoke方法,然后才会调用目标对象的方法

2 代理类 – TransactionInvocationhandler

// 导入cglib包的InvocationHandler 
public class TransactionInvocationhandler implements InvocationHandler {/*注入真实对象:程序运行起来之后才会知道是什么对象*/private Object object;public void setObject(Object object) {this.object = object;}public Object getObject() {return object;}/*注入扩展对象:事务对象*/private TransactionManager transactionManager;public void setTransactionManager(TransactionManager transactionManager) {this.transactionManager = transactionManager;}/*将真实业务方法和扩展方法组合执行*/@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable {Object o=null;try {/*开启事务*/transactionManager.begin();/*执行真实对象的方法:反射调用类成员方法*/o= method.invoke(object,args);/*设置异常*/
//            int num=10/0;/*提交事务*/transactionManager.commit();} catch (Exception e) {e.printStackTrace();/*回滚事务*/transactionManager.rollback();}return o;}
}

3 测试类

// 只须修改代理类和测试类 其他与jdk代理相同
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-core.xml")
public class EmployeeServiceTest {@Autowiredprivate TransactionInvocationhandler transactionInvocationhandler;@Testpublic void emp_save() {//创建代理对象的生成类对象 通过他创建代理对象Enhancer enhancer=new Enhancer();//设置代理对象和真实对象的继承关系 将真实对象设为代理对象的父类enhancer.setSuperclass(transactionInvocationhandler.getObject().getClass());//设置代理对象需要执行的操作 形参为callback 实际传递为他的继承类的实现类enhancer.setCallback(transactionInvocationhandler);//创建代理对象EmployeeServiceImpl employeeService = (EmployeeServiceImpl) enhancer.create();//调用代理对象的方法employeeService.save("陈汉生","admin");}
}

五 动态代理小结

1 JDK 动态代理

  Java 动态代理是使用 java.lang.reflect 包中的 Proxy 类与 InvocationHandler 接口这两个来完成的。要使用 JDK 动态代理,真实类必须实现接口。JDK 动态代理将会拦截所有 pubic 的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
  动态代理的最小单位是类(类中某些方法都会被处理),如果只想拦截一部分方法,可以在 invoke 方法中对要执行的方法名进行判断。(代理类与真实类共同实现相同接口)

2 CGLIB 动态代理

  CGLIB 可以生成真实类的子类,并重写父类非 final 修饰符的方法。要求类不能是 final 的,要拦截的方法要是非 final、非 static、非 private 的。
  动态代理的最小单位是类(类中某些方法都会被处理),如果只想拦截一部分方法,可以在 invoke 方法中对要执行的方法名进行判断。(代理类是继承真实类)

3 选择

  从性能上看:Javassit 优于 CGLIB 优于 JDK,JDK 动态代理是基于实现接口的,CGLIB 和 Javassit 是基于继承真实类的。
  真实类实现了接口,优先选用 JDK 动态代理。若真实类没实现任何接口,使用 Javassit 和 CGLIB 动态代理。

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

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

相关文章

电脑数据恢复软件哪个有效好用?十大电脑数据恢复软件排行

在数字时代&#xff0c;数据就是一切。从珍贵的家庭照片和重要的工作文档到最喜欢的音乐和电影&#xff0c;我们的生活越来越多地存储在各种设备上。系统崩溃、意外删除或恶意病毒都可能使您的宝贵数据瞬间消失。这就是数据恢复工具的用武之地。 十大电脑数据恢复软件排行 这些…

Integer.valueOf方法详解

Integer.valueOf 是 Java 中 Integer 类的一个静态方法&#xff0c;它用于将给定的字符串或基本数据类型转换成一个 Integer 对象。 使用场景 从字符串转换&#xff1a;将字符串形式的数字转换为 Integer 对象。 Integer num Integer.valueOf("123");从基本数据类…

论文阅读2---多线激光lidar内参标定原理

前言&#xff1a;该论文介绍多线激光lidar的标定内参的原理&#xff0c;有兴趣的&#xff0c;可研读原论文。 1、标定参数 rotCorrection&#xff1a;旋转修正角&#xff0c;每束激光的方位角偏移&#xff08;与当前旋转角度的偏移&#xff0c;正值表示激光束逆时针旋转&…

关于一个QT程序的简单破解思路(不需要分析信号和槽的方法,通用所有程序的破解思路)

几年前,公司买了台国产贴片机,里面的主程序是QT编写,运行在WINDOW XP系统上。主程序打开的界面,如图: 我来简单介绍下程序界面,各位读者不需要搞明白功能,只要知道大体的流程即可。 分析主界面: 一、左边的列表&#xff1a; 贴片生产文件,里面包括了贴片时元器件的坐标、飞达…

C#winform上位机开发学习笔记11-串口助手接收数据用波形显示功能添加

1.功能描述 接收串口数据&#xff0c;并将收到的十六进制数据用坐标系的方式将数据波形展示出来 2.代码部分 步骤1&#xff1a;定义链表&#xff0c;用于数据保存 //数据结构-线性链表private List<byte> DataList new List<byte>(); 步骤2&#xff1a;定义波…

shell脚本2

在自定义变量当中&#xff0c;不可以以数字开头 变量追加值 在变量名后要写的东西 read -p &#xff1a;交互式输入变量值&#xff0c;然后使用变量 自定义变量 export 全局变量 如果想要bash里面的所有进程都能看见变量&#xff0c;加入export 父进程 子进程…

计算机毕业设计 基于SpringBoot的民宿租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Sentinel 新版本发布,提升配置灵活性以及可观测配套

作者&#xff1a;屿山 基本介绍 Sentinel 是阿里巴巴集团开源的&#xff0c;面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;承接了阿里巴巴近 15 年的双十一大促流量的核心场景&#xff0c;例如秒杀、冷启动、消息削峰填谷、集群流量控制、实时熔断下游不可用服…

考研C语言刷题基础篇之分支循环结构基础(二)

目录 第一题分数求和 第二题&#xff1a;求10 个整数中最大值 第三题&#xff1a;在屏幕上输出9*9乘法口诀表 第四题&#xff1a;写一个代码&#xff1a;打印100~200之间的素数 第五题&#xff1a;求斐波那契数的第N个数 斐波那契数的概念&#xff1a;前两个数相加等于第三…

2023 工业 AR 关键词:纵深和开拓

2023 年&#xff0c;以虚实融合、工业元宇宙为代表的“新数字化”升级在工业制造领域达成共识。 ▲五部委联合印发元宇宙行动计划 通过发展元宇宙赋能新型工业化 而相对过去几年的行业渗透广、落地场景多样的 AR 业务拓展与合作&#xff0c;#纵深和#开拓&#xff0c;成为 2023…

80端口被占用解决思路

普及一个概念&#xff1a;80端口是 HTTP&#xff08;HyperText Transport Protocol)即超文本传输协议开放的&#xff0c;此为上网冲浪使用次数最多的协议&#xff0c;主要用于WWW&#xff08;World Wide Web&#xff09;即万维网传输信息的协议。 我们使用 http 域名访问时都会…

Vue3 ref与reactive

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

HarmonyOS鸿蒙学习基础篇 - 基本语法概述

书接上文 HarmonyOS鸿蒙学习基础篇 - 运行第一个程序 Hello World 基本语法概述 打开 entry>src>main>ets>pages>index.ets 代码如下代码详细解释如下&#xff1a; Entry //Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中&#xff0c;最多可以使用…

Dify学习笔记-应用发布(四)

1、发布为公开 Web 站点 使用 Dify 创建 AI 应用的一个好处在于&#xff0c;你可以在几分钟内就发布一个可供用户使用的 Web 应用&#xff0c;该应用将根据你的 Prompt 编排工作。 如果你使用的是自部署的开源版&#xff0c;该应用将运行在你的服务器上 如果你使用的是云服务&…

2024年跨境电商上半年有哪些营销节日?

2024年伊始&#xff0c;跨境电商开启新一轮的营销竞技&#xff0c;那么首先需要客户需求&#xff0c;节假日与用户需求息息相关&#xff0c;那么接下来小编为大家整理2024上半年海外都有哪些节日和假期&#xff1f;跨境卖家如何见针对营销日历选品&#xff0c;助力卖家把握2024…

Java框架篇面试题

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于java面试题系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基…

flutter底层架构初探

本文出处&#xff1a;​​​​​​​​​​​​​Flutter 中文开发者网站 架构 embedder嵌入层 提供程序入口&#xff08;其他原生应用也采用此方式&#xff09;&#xff0c;程序由此和底层操作系统协调&#xff08;surface渲染、辅助功能和输入服务&#xff0c;管理事件循环…

书生·浦语大模型--第四节课笔记--XTuner大模型单卡低成本微调

文章目录 Finetune简介指令跟随微调增量预训练微调LoRA QLoRA XTuner介绍快速上手 8GB显卡玩转LLM动手实战环节 Finetune简介 增量预训练和指令跟随 通过指令微调获得instructed LLM 指令跟随微调 一问一答的方式进行 对话模板 计算损失 增量预训练微调 不需要问题只…

微签电子印章系统赋能国泰基金办公自动化升级

近期&#xff0c;国泰基金引入微签电子印章系统&#xff0c;通过印章服务器自动化印章方案&#xff0c;成功搭建起电子印章自动化平台&#xff0c;主要解决了其账单数量过多、极度耗费人力的难题&#xff0c;缩短了印章发送流程和时间&#xff0c;提升了国泰基金的整体办公效率…

Prometheus 架构全面解析

在本指南中&#xff0c;我们将详细介绍 Prometheus 架构。 Prometheus 是一个用 Golang 编写的开源监控和告警系统&#xff0c;能够收集和处理来自各种目标的指标。您还可以查询、查看、分析指标&#xff0c;并根据阈值收到警报。 此外&#xff0c;在当今世界&#xff0c;可观…