
Java中的代理
动态性:代理类是在程序运行时生成的,相比静态生成,实现更加灵活。 可扩展性:可以动态添加或更改接口实现,而无需重新编译代码。 遥远接口支持:代理可以跨越不同的机器,适用于远程受话者的编程。
发布日期:2021-05-20 04:05:55
浏览次数:22
分类:精选文章
本文共 2739 字,大约阅读时间需要 9 分钟。
利用动态代理,可以在运行时创建实现一组给定接口的新类。当在编译时期无法确定需要实现哪些接口时,这种技术特别有用。动态代理的核心在于使用调用处理器(InvocationHandler)来拦截方法调用,并在方法执行前或后进行处理。
何时使用代理
在运行时决定哪些接口需要实现时,使用代理机制是理想的。这种方法非常有用,特别是在以下情况下:
- 接口不确定性:当你不知道具体需要实现哪些接口时,动态代理允许你在运行时指定这些接口。
- 需要监控或修改方法行为:你可以拦截方法调用并在执行前或后添加自定义逻辑,例如日志记录、输入验证或其他处理。
- 实现平台无关的接口:不同平台可能有不同的接口实现,而动态代理允许你包装这些接口以适应一致的方法调用。
代理类的工作原理
动态代理机制通过以下步骤实现:
指定接口和处理器:使用Proxy.newProxyInstance
方法创建代理对象。该方法需要:
- 类加载器:决定使用哪个类加载器。
- 接口数组:指定需要实现的所有接口。
- 调用处理器:负责拦截方法调用并执行自定义逻辑。
创建代理类:Proxy类生成一个动态代理类,该类实现了所有指定接口。该代理类包含对调用处理器的委派机制,确保所有方法调用通过调用处理器进行处理。
拦截方法调用:当通过代理对象调用任何接口方法时,调用处理器的invoke
方法会被触发。这允许你在方法执行前或后进行任何自定义操作。
创建代理对象
要手动创建动态代理对象,可以按照以下步骤操作:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Arrays;import java.util.Random;public class ProxyTest { public static void main(String[] args) { Object[] elements = new Object[1000]; for (int i = 0; i < elements.length; i++) { Integer value = i + 1; TraceHandler handler = new TraceHandler(value); Object proxy = Proxy.newProxyInstance( ClassLoader.getSystemClassLoader(), new Class[]{Comparable.class}, handler ); elements[i] = proxy; } Integer key = new Random().nextInt(elements.length) + 1; int result = Arrays.binarySearch(elements, key); if (result >= 0) { System.out.println(elements[result]); } }}class TraceHandler implements InvocationHandler { private Object target; public TraceHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.print(target); System.out.print("." + method.getName() + "("); if (args != null) { for (int i = 0; i < args.length; i++) { System.out.print(args[i]); if (i < args.length - 1) { System.out.print(','); } } } System.out.println(")"); return method.invoke(target, args); }}
动态代理的特性
讨论
在示例中,每个代理对象实现了Comparable
接口,但实现的是动态生成的代理类,而不是实际的Integer
类。这意味着,当调用compareTo
方法时,调用处理器会被触发,并在实际的对象上执行compareTo
。
if (elements[i].compareTo(key) < 0) { ...}
在这里,elements[i]
是代理对象,而不是实际的Integer
对象。调用处理器将拦截compareTo
方法,并打印出方法执行情况,然后调用实际对象的方法。
性能考虑
动态代理虽然提供了灵活性,但在性能上可能需要引入一定的开销。通过优化调用处理器和减少中间步骤,可以尽量降低性能开销。例如,可以缓存方法调用或避免不必要的操作。
总结
动态代理是一种强大的工具,特别适用于以下场景:
- 接口实现不确定性:运行时确定接口,动态实现。
- 规范化处理:统一处理不同实现的方法调用。
- 监控与安全:拦截敏感操作,执行安全检查或监控日志。
通过合理使用动态代理,可以显著提高代码的灵活性和可维护性。
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2025年04月23日 23时05分16秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
区块链会2020再次爆发,先学点DAPP压压惊,跟我一起学《区块链DApp入门实战》
2019-03-16
问题解决28:微信网页授权出现redicet_uri 参数错误
2019-03-16
LeakCanary 中文使用说明
2019-03-16
反转链表,(5)
2019-03-16
Camera (api1)的打开过程
2019-03-16
wxwidgets绘图
2019-03-16
wxwidgets事件处理
2019-03-16
用OpenCv转换原始图像数据到wximage
2019-03-16
codeblocks下wxWidgets编译与配置
2019-03-16
OpenCv+wxwidgets尝试
2019-03-16
wxwidgets自定义事件+调试
2019-03-16
wxwidgets编写多线程程序--wxThread
2019-03-16
BUUCTF:[湖南省赛2019]Findme
2019-03-16
p144循环网络
2019-03-17
三维点云处理
2019-03-17
springboot security 基于redis的session共享(7)
2019-03-17
vue 权限管理 菜单按钮权限控制(7)
2019-03-17
vue 权限管理 主题切换(8)
2019-03-17
Qt 在Excel文件中Chart绘图
2019-03-17
01-webpack5理解及配置
2019-03-17