java 代理模式及动态代理机制深入分析

代理设计模式
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便
在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象
图 1. 代理模式类图
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托 类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
java动态代理
相关的类和接口
要了解 Java 动态代理的机制,首先需要了解以下相关的类或接口:
· java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
清单 1. Proxy 的静态方法
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器 static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 static Class getProxyClass(ClassLoader loader, Class[] interfaces) // 方法 3:该方法用于判断指定类对象是否是一个动态代理类 static boolean isProxyClass(Class cl) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
清单 2. InvocationHandler 的核心方法
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象 // 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行 Object invoke(Object proxy, Method method, Object[] args)
每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象(参见 Proxy 静态方法 4 的第三个参数)。
· java.lang.ClassLoader:这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何个 .class 文件中。
每次生成动态代理类对象时都需要指定一个类装载器对象(参见 Proxy 静态方法 4 的第一个参数)
代理机制及其特点
首先让我们来了解一下如何使用 Java 动态代理。具体有如下四步骤:
1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
清单 3. 动态代理对象创建过程
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..);
// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });
// 通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
// 通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程,所以简化后的过程如
清单 4. 简化的动态代理对象创建过程
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
InvocationHandler handler = new InvocationHandlerImpl(..);
// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,
new Class[] { Interface.class },
handler );
下面我们来看一个简单实现动态代理的例子:
1.代理类和真实类接口:
public interface Subject
{
public void request();
}
2.真实类:
public class RealSubject implements Subject
{
public void request()
{
System.out.println("From real subject!");
}}
3.具体代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicSubject implements InvocationHandler
{
private Object sub;
public DynamicSubject(Object obj)
{
this.sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("before calling: " + method);
method.invoke(sub, args);
System.out.println(args == null);
System.out.println("after calling: " + method);
return null;
}
注:该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象。 此外,该类还实现了invoke方法,该方法中的method.invoke其实就是调用被代理对象的将要 执行的方法,方法参数是sub,表示该方法从属于sub,通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一些额外方法。
4.客户端调用示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client
{
public static void main(String[] args)
{
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
Class<?> classType = handler.getClass();
// 下面的代码一次性生成代理
Subject subject = (Subject) Proxy.newProxyInstance(classType
.getClassLoader(), realSubject.getClass().getInterfaces(),
handler);
subject.request();
System.out.println(subject.getClass());
}
}
接下来让我们来了解一下 Java 动态代理机制 Proxy 的构造方法:
清单 6. Proxy 构造方法
// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用
private Proxy() {}
// 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
protected Proxy(InvocationHandler h) {this.h = h;}
接着,可以快速浏览一下 newProxyInstance 方法,因为其相当简单:
清单 7. Proxy 静态方法 newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
// 检查 h 不为空,否则抛异常
if (h == null) {
throw new NullPointerException();
}
// 获得与制定类装载器和一组接口相关的代理类类型对象
Class cl = getProxyClass(loader, interfaces);
// 通过反射获取构造函数对象并生成代理类实例
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) { throw new InternalError(e.toString());
} catch (IllegalAccessException e) { throw new InternalError(e.toString());
} catch (InstantiationException e) { throw new InternalError(e.toString());
} catch (InvocationTargetException e) { throw new InternalError(e.toString());
}
}
由此可见,动态代理真正的关键是在 getProxyClass 方法,该方法负责为一组接口动态地生成代理类类型对象。
有很多条理由,人们可以否定对 class 代理的必要性,但是同样有一些理由,相信支持 class 动态代理会更美好。接口和类的划分,本就不是很明显,只是到了 Java 中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此 外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。
但是,不完美并不等于不伟大,伟大是一种本质,Java 动态代理就是佐例。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# java
# 代理模式及动态代理机制
# 代理模式及动态代理机制详细介绍
# Java简单实现动态代理模式过程解析
# Java代理模式实例详解【静态代理与动态代理】
# Java动态代理模式的深入揭秘
# Java设计模式之动态代理模式实例分析
# JAVA动态代理模式(从现实生活角度理解代码原理)
# 详解java动态代理模式
# java代理模式与动态代理模式详解
# 代理模式之Java动态代理实现方法
# Java代理模式与动态代理之间的关系以及概念
# 这是
# 为其
# 自己的
# 实现了
# 是一种
# 第一个
# 让我们
# 他对
# 第三个
# 并能
# 客户端
# 是一个
# 直接调用
# 是在
# 也有
# 很好
# 抽象类
# 子类
# 有很多
# 都能
相关文章:
建站主机选购指南:核心配置与性价比推荐解析
建站主机助手选型指南:2025年热门推荐与高效部署技巧
制作农业网站的软件,比较好的农业网站推荐一下?
如何在阿里云服务器自主搭建网站?
行程制作网站有哪些,第三方机票电子行程单怎么开?
深圳企业网站制作设计,在深圳如何网上全流程注册公司?
建站之星如何防范黑客攻击与数据泄露?
网站制作软件有哪些,制图软件有哪些?
制作网站的过程怎么写,用凡科建站如何制作自己的网站?
天津个人网站制作公司,天津网约车驾驶员从业资格证官网?
如何选择适配移动端的WAP自助建站平台?
定制建站流程解析:需求评估与SEO优化功能开发指南
建站之星后台管理如何实现高效配置?
济南专业网站制作公司,济南信息工程学校怎么样?
想学网站制作怎么学,建立一个网站要花费多少?
网站建设制作、微信公众号,公明人民医院怎么在网上预约?
淘宝制作网站有哪些,淘宝网官网主页?
宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?
建站主机与虚拟主机有何区别?如何选择最优方案?
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
网站制作外包价格怎么算,招聘网站上写的“外包”是什么意思?
在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
建站之星安装提示数据库无法连接如何解决?
如何挑选高效建站主机与优质域名?
建站之星伪静态规则如何设置?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
如何选择高效可靠的多用户建站源码资源?
香港服务器建站指南:免备案优势与SEO优化技巧全解析
Python lxml的etree和ElementTree有什么区别
网站制作报价单模板图片,小松挖机官方网站报价?
定制建站是什么?如何实现个性化需求?
长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?
北京制作网站的公司排名,北京三快科技有限公司是做什么?北京三快科技?
如何通过虚拟主机快速完成网站搭建?
网站制作费用多少钱,一个网站的运营,需要哪些费用?
如何通过建站之星自助学习解决操作问题?
C++如何将C风格字符串(char*)转换为std::string?(代码示例)
实例解析Array和String方法
定制建站方案优化指南:企业官网开发与建站费用解析
高端网站建设与定制开发一站式解决方案 中企动力
如何快速生成ASP一键建站模板并优化安全性?
如何选择服务器才能高效搭建专属网站?
表情包在线制作网站免费,表情包怎么弄?
制作网站的模板软件,网站怎么建设?
如何在云指建站中生成FTP站点?
如何选择PHP开源工具快速搭建网站?
建站之星后台管理系统如何操作?
黑客如何利用漏洞与弱口令入侵网站服务器?
javascript中对象的定义、使用以及对象和原型链操作小结
*请认真填写需求信息,我们会在24小时内与您取得联系。