java 中动态代理机制的实例讲解
发布时间 - 2026-01-11 03:19:13 点击率:次java 中动态代理机制的实例讲解

在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:
InvocationHandler:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?
- proxy: 指代我们所代理的那个真实对象
- method: 指代的是我们所要调用真实对象的某个方法的Method对象
- args: 指代的是调用真实对象某个方法时接受的参数
如果不是很明白,等下通过一个实例会对这几个参数进行更深的讲解。
接下来我们来看看Proxy这个类:
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:
- loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
- interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
- h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
好了,在介绍完这两个接口(类)以后,我们来通过一个实例来看看我们的动态代理模式是什么样的:
首先我们定义了一个Subject类型的接口,为其声明了两个方法:
public interface Subject
{
public void rent();
public void hello(String str);
}
接着,定义了一个类来实现这个接口,这个类就是我们的真实对象,RealSubject类:
public class RealSubject implements Subject
{
@Override
public void rent()
{
System.out.println("I want to rent my house");
}
@Override
public void hello(String str)
{
System.out.println("hello: " + str);
}
}
下一步,我们就要定义一个动态代理类了,前面说个,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外:
public class DynamicProxy implements InvocationHandler
{
// 这个就是我们要代理的真实对象
private Object subject;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object subject)
{
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("before rent house");
System.out.println("Method:" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent house");
return null;
}
}
最后,来看看我们的Client类:
/**
* Java学习交流QQ群:589809992 我们一起学Java!
*/
public class Client
{
public static void main(String[] args)
{
// 我们要代理的真实对象
Subject realSubject = new RealSubject();
// 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(realSubject);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
}
}
我们先来看看控制台的输出:
$Proxy0 before rent house Method:public abstract void com.xiaoluo.dynamicproxy.Subject.rent() I want to rent my house after rent house before rent house Method:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String) hello: world after rent house
我们首先来看看 $Proxy0 这东西,我们看到,这个东西是由 System.out.println(subject.getClass().getName()); 这条语句打印出来的,那么为什么我们返回的这个代理对象的类名是这样的呢?
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
可能我以为返回的这个代理对象会是Subject类型的对象,或者是InvocationHandler的对象,结果却不是,首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。
同时我们一定要记住,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
接着我们来看看这两句
subject.rent(); subject.hello(“world”);
这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的 handler 中的invoke方法去执行,而我们的这个 handler 对象又接受了一个 RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用 handler 中的invoke方法去执行:
/**
* Java学习交流QQ群:589809992 我们一起学Java!
*/
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("before rent house");
System.out.println("Method:" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent house");
return null;
}
我们看到,在真正通过代理对象来调用真实对象的方法的时候,我们可以在该方法前后添加自己的一些操作,同时我们看到我们的这个 method 对象是这样的:
public abstract void com.xiaoluo.dynamicproxy.Subject.rent() public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
正好就是我们的Subject接口中的两个方法,这也就证明了当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。
这就是我们的java动态代理机制。
本篇随笔详细的讲解了java中的动态代理机制,这个知识点非常非常的重要,包括我们Spring的AOP其就是通过动态代理的机制实现的,所以我们必须要好好的理解动态代理的机制。
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# java
# 动态代理
# 动态代理机制的详解
# 动态代理的分析
# 详解Java的Proxy动态代理机制
# 详解Java Proxy动态代理机制
# 浅谈Java 代理机制
# Java动态代理机制的实例详解
# 带你深入了解java-代理机制
# 的是
# 自己的
# 来看看
# 就会
# 方法来
# 我们可以
# 这组
# 转化为
# 我要
# 是在
# 跳转到
# 就能
# 是这样
# 当我
# 将其
# 这两个
# 第二个
# 这个时候
# 我们一起
# 这三个
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践
如何在Windows环境下新建FTP站点并设置权限?
如何在Windows服务器上快速搭建网站?
教你用AI将一段旋律扩展成一首完整的曲子
Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】
Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南
Laravel如何与Pusher实现实时通信?(WebSocket示例)
Python文件流缓冲机制_IO性能解析【教程】
Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践
Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程
Laravel如何使用集合(Collections)进行数据处理_Laravel Collection常用方法与技巧
EditPlus中的正则表达式 实战(4)
再谈Python中的字符串与字符编码(推荐)
如何用y主机助手快速搭建网站?
如何使用 jQuery 正确渲染 Instagram 风格的标签列表
Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南
太平洋网站制作公司,网络用语太平洋是什么意思?
Laravel如何优化应用性能?(缓存和优化命令)
黑客如何利用漏洞与弱口令入侵网站服务器?
Angular 表单中正确绑定输入值以确保提交与验证正常工作
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
HTML 中如何正确使用模板变量为元素的 name 属性赋值
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
5种Android数据存储方式汇总
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
网站制作企业,网站的banner和导航栏是指什么?
如何用PHP快速搭建高效网站?分步指南
为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】
Laravel怎么导出Excel文件_Laravel Excel插件使用教程
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】
Win11怎么开启自动HDR画质_Windows11显示设置HDR选项
js实现获取鼠标当前的位置
如何用美橙互联一键搭建多站合一网站?
公司门户网站制作流程,华为官网怎么做?
在线制作视频的网站有哪些,电脑如何制作视频短片?
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
如何自定义建站之星模板颜色并下载新样式?
如何快速登录WAP自助建站平台?
Java类加载基本过程详细介绍
详解jQuery停止动画——stop()方法的使用
Laravel怎么在Blade中安全地输出原始HTML内容
昵图网官方站入口 昵图网素材图库官网入口
大型企业网站制作流程,做网站需要注册公司吗?
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】

