[Java]代理模式

news/2025/1/4 9:58:59/文章来源:https://www.cnblogs.com/cnb-yuchen/p/18002823

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://www.cnblogs.com/cnb-yuchen/p/18002823
出自【进步*于辰的博客】

参考笔记一,P83。

代理模式分为静态代理和动态代理,比较简单,直接上示例,一目了然。为降低大家阅读成本,所有示例的打印结果都相同:

打开事务
转账金额:100
关闭事务
1

大家可自行cp测试。

静态代理

1:面向接口、目标类与代理类实现于同一接口。

// 目标类和代理类的公共接口
interface IService {int transfer(int account);
}// 目标类
class Target implements IService {public int transfer(int account) {System.out.println("转账金额:" + account);return 1;}
}// 代理类
class Proxy implements IService {private Target tar;public Proxy(Target tar) {this.tar = tar;}public int transfer(int account) {System.out.println("打开事务");int x = tar.transfer(account);System.out.println("关闭事务");return x;}
}class Test {public static void main(String[] args) {Proxy proxy = new Proxy(new Target());int x = proxy.transfer(100);System.out.println(x);}
}

2:面向继承、代理类继承于目标类。

class Target {public int transfer(int account) {System.out.println("转账金额:" + account);return 1;}
}class Proxy extends Target {public int transfer(int account) {System.out.println("打开事务");int x = super.transfer(account);System.out.println("关闭事务");return x;}
}class Test {public static void main(String[] args) {Proxy proxy = new Proxy();int x = proxy.transfer(100);System.out.println(x);}
}

动态代理

静态代理需要手动创建代理类,冗余。换个思路,反射可以根据Class信息创建实例,故可以通过反射为目标对象创建代理对象,则无需创建代理类,这就是“动态代理”。

JDK动态代理

面向接口,是JDK自带的。

interface IService {int transfer(int account);
}class Target implements IService {public int transfer(int account) {System.out.println("转账金额:" + account);return 1;}
}class Test {public static void main(String[] args) {Target tar = new Target();/*** 通过 Proxy.newProxyInstance() 创建代理对象。*     第一个参数是目标对象的类加载器,指定为哪个目标对象创建代理对象;*     第二个参数是目标对象实现的接口,指定目标对象和代理对象的公共接口;*     第三个参数是拦截器对象,指定用哪个拦截器来创建代理对象,需要实现 InvocationHandler 接口。*/// 由于 proxyInstance  是通过反射创建,存储于JVM,匿名(文末说明),故上转为 IServiceIService proxyInstance = (IService) Proxy.newProxyInstance(tar.getClass().getClassLoader(),tar.getClass().getInterfaces(),new InvocationHandler() {/*** 代理(调用 transfer())时执行的方法* @param proxy  代理对象,即 proxyInstance,暂不知如何使用* @param method 目标对象的 Method 的 class 对象* @param args   目标对象的 Method 的形参数组*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("打开事务");// invoke() 是反射中 Method 对象执行时调用的方法,故动态代理是通过反射调用目标对象被代理的方法Object result = method.invoke(tar, args);System.out.println("关闭事务");return result;}});int x = proxyInstance.transfer(100);System.out.println(x);}
}

可以使用Lambda表达式省略new InvocationHandler()

Cglib动态代理

面向继承,基于Spring。

class Target {public int transfer(int account) {System.out.println("转账金额:" + account);return 1;}
}// 动态代理类(拦截器)
class DynamicProxy implements MethodInterceptor {private Object tar;public DynamicProxy(Object tar) {this.tar = tar;}public Object createProxy() {Enhancer proxy = new Enhancer();// Enhancer 类是一种类生成器proxy.setCallback(this);// 设置拦截器,即自身proxy.setSuperclass(tar.getClass());// 设置父类,指定为哪个目标对象创建代理对象return proxy.create();// 创建代理对象}/*** 代理(调用 transfer())时执行的方法* @param proxy       代理对象,即 proxyInstance,暂不知如何使用* @param method      目标对象的 Method 的 class对象* @param args        目标对象的 Method 的参数数组* @param methodProxy 代理方法,即 Target.transfer(),暂不知如何使用*/@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("打开事务");Object result = method.invoke(tar, args);System.out.println("关闭事务");return result;}
}class Test {public static void main(String[] args) {Target target = new Target();Target proxyInstance = (Target) new DynamicProxy(target).createProxy();int x = proxyInstance.transfer(100);System.out.println(x);}
}

同样可以使用Lambda表达式优化,不过代理对象的创建(proxy.create())需要对Enhancer 类的属性进行一些设置,故进行了封装。

注意:两种动态代理都可以拦截所有方法,如:toString()hashcode()。但不能拦截由final修饰的方法,如:getClass()

扩展

JDK动态代理的核心是“面向接口”,实际上并不需要目标对象(公共接口的实现),也就是这样:

interface IService {int transfer(int account);
}class Test {public static void main(String[] argx) {Class z1 = IService.class;IService proxyInstance = (IService) Proxy.newProxyInstance(z1.getClassLoader(),new Class[] { z1 },(proxy, method, args) -> {System.out.println("打开事务");System.out.println("关闭事务");return 1;});int x = proxyInstance.transfer(100);System.out.println(x);}
}

没有目标对象,还是代理模式吗?又有什么意义?

Mybatis为Mapper接口创建代理对象使用的就是这种方式,不需要为Mapper接口创建实现类,我寻得一篇文章 → 一文搞懂Java动态代理:为什么Mybatis Mapper不需要实现类?(转发),那位博主讲述得狠详细,大家自行转站学习,我在此就不赘述了。

最后

本文中的例子是为了阐述静态代理和动态代理的实现思想、方便大家理解而简单举出的,不一定有实用性,仅是抛砖引玉。

本文完结。

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

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

相关文章

lvs+dr+httpd+keepalived高可用部署

lvs+dr+httpd+keepalived高可用部署参考文档:http://blog.csdn.net/m582445672/article/details/7670015 a、 keepalived 是lvs 的扩展项目,因此它们之间具备良好的兼容性。这点应该是keepalived 部署比其他类似工具能更简洁的原因吧! b、 通过对服务器池对象的健康检查,实…

《数字经济:行业产业链》全景梳理及区域热力图

行业主要上市公司:中兴通讯(000063)、大华股份(002236)、中科创达(300496)、软通动力(301236)、奇安信(688561)、同方股份(600100)、……等 本文核心数据:《数字经济:产业链 》、《数字经济:产业链 - 生态图谱》、《“产业数字化” 和 “数字产业化” 上市公司…

《数字经济行业产业链》全景梳理及区域热力图

行业主要上市公司:中兴通讯(000063)、大华股份(002236)、中科创达(300496)、软通动力(301236)、奇安信(688561)、同方股份(600100)、……等 本文核心数据:《数字经济产业链 》、《数字经济产业链生态图谱》、《产业数字化 和 数字产业化上市公司区域分布 TOP5》、…

【长路经】C#读取文件抛出FileNotFoundException异常

前言 在winform中读取文件信息时,突然抛出了FileNotFoundException的异常,但是本地是有这个文件的。 随后找到了这个文件,查看属性,[位置]属性,多了"\\?\"的前缀,百度得知这是windows对长路经的处理。需要注意: 目前在NetFx框架下,才有这个问题。 在NetCore…

【unity】学习制作类银河恶魔城游戏-5-

在-1---4-中,了解了unity的基础操作,从创建一个人物开始,通过状态机和代码完善人物的各种功能达到预期效果,随着功能的越来越多,状态机的处理也就越发麻烦,因此,从零开始设计一个合理的状态机很有必要 梦开始的地方 创建一个新的项目修改舒服的布局创建状态机,通过脚本…

CH340C 请求 USB 设备描述符失败

简短不看版如果出现上述状况,说明线有问题:线的确是数据线(不是电源线),但是不是能与CH340正常通讯的数据线(数据线的数据传输功能有问题。 需要更换其它数据线.前文该文分享CH340驱动使用过程可能出现的问题,以下出现的问题解决方案都建立在CH340硬件正常的情况下。CH3…

CH32V203F6P6-TSSOP20测试之02

一、问题思考 直接用官方提供的例程,为何下载程序后没有什么响应,难道自己设计的电路有什么不妥? 于是,对于电路进行具体分析,结果发现: 第一、官方的BOOT0采用杜邦线连接,在芯片手册好像找不到关于BOOT0的叙述,仅仅在《CH32V20x评估板说明书》中看到:也就是说,这芯片…

PVC

短线反弹

大语言模型提示技巧(一)-指令要清晰、具体

在与大语言模型对话时,应该提供尽可能清晰和具体的指令来表达希望模型执行的操作,这将有助于模型给出接近你所期待的输出,并降低得到无关或不正确回复的可能性。但需要注意的是,编写清晰的指令不意味着编写简短的指令,事实上,更长的提示实际上更清晰且提供了更多的上下文…

再见2024,一个算法研发的个人年终总结

元旦将近,显然又是一年岁末。 同事开始讨论中午吃什么,以及晚上的跨年计划之类的大问题。 我开始努力回想自己的2024,秉承着毕业以来每年写个人总结的习惯, 也因为近年来自己的节奏和生活越来越快,只能在年终的节点停下来回顾下自己的历程。 前言 我打开了自己的相册,下面…

; 自动设置电脑快捷键的AutoHotkey脚本程序源代码 2025年1月1日

; 自动设置电脑快捷键的AutoHotkey脚本程序源代码 2025年1月1日 ; 自动设置电脑快捷键的AutoHotkey脚本程序源代码 2025年1月1日;======== 设置显示或者隐藏MasterSeeker和Total Commander主窗口的快捷键的AutoHotkey脚本2024.10.21 ========= ; 此脚本从此行开始 ; D:\app\Re…

记 Redisson 报错 attempt to unlock lock, not locked by current thread

原文:记一次 Redisson 线上问题 → 你怎么能释放别人的锁错误信息: attempt to unlock lock, not locked by current thread by node id: b9df1975-5595-42eb-beae-bdc5d67bce49 thread-id: 52查看日志,找到对应的堆栈信息 Exception in thread "thread0" java.la…