Java动态代理实现_动力节点Java学院整理
发布时间 - 2026-01-11 02:37:40 点击率:次动态代理作为代理模式的一种扩展形式,广泛应用于框架(尤其是基于AOP的框架)的设计与开发,本文将通过实例来讲解Java动态代理的实现过程。

通常情况下,代理模式中的每一个代理类在编译之后都会生成一个class文件,代理类所实现的接口和所代理的方法都被固定,这种代理被称之为静态代理(Static Proxy)。那么有没有一种机制能够让系统在运行时动态创建代理类?答案就是本文将要介绍的动态代理(Dynamic Proxy)。动态代理是一种较为高级的代理模式,它在事务管理、AOP(Aspect-OrientedProgramming,面向方面编程)等领域都发挥了重要的作用。
在传统的代理模式中,客户端通过Proxy类调用RealSubject类的request()方法,同时还可以在代理类中封装其他方法(如preRequest()和postRequest()等)。如果按照这种方法使用代理模式,那么代理类和真实主题类都应该是事先已经存在的,代理类的接口和所代理方法都已明确指定,如果需要为不同的真实主题类提供代理类或者代理一个真实主题类中的不同方法,都需要增加新的代理类,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数。动态代理可以让系统能够根据实际需要来动态创建代理类,让同一个代理类能够代理多个不同的真实主题类而且可以代理不同的方法。
从JDK 1.3开始,Java语言提供了对动态代理的支持,Java语言实现动态代理时需要用到位于java.lang.reflect包中的一些类,现简要说明如下:
(1) Proxy类
Proxy类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类,它最常用的方法如下:
- public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces):该方法用于返回一个Class类型的代理类,在参数中需要提供类加载器并需要指定代理的接口数组(与真实主题类的接口列表一致)。
- public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h):该方法用于返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类所实现的接口列表(与真实主题类的接口列表一致),第三个参数h表示所指派的调用处理程序类。
(2) InvocationHandler接口
InvocationHandler接口是代理处理程序类的实现接口,该接口作为代理实例的调用处理者的公共父类,每一个代理类的实例都可以提供一个相关的具体调用处理者(InvocationHandler接口的子类)。在该接口中声明了如下方法:
public Object invoke(Objectproxy, Method method, Object[] args):该方法用于处理对代理类实例的方法调用并返回相应的结果,当一个代理实例中的业务方法被调用时将自动调用该方法。invoke()方法包含三个参数,其中第一个参数proxy表示代理类的实例,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。
动态代理类需要在运行时指定所代理真实主题类的接口,客户端在调用动态代理对象的方法时,调用请求会将请求自动转发给InvocationHandler对象的invoke()方法,由invoke()方法来实现对请求的统一处理。
下面通过一个简单实例来学习如何使用动态代理模式:
Sunny软件公司欲为公司OA系统数据访问层DAO增加方法调用日志,记录每一个方法被调用的时间和调用结果,现使用动态代理进行设计和实现。
本实例完整代码如下所示:
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.GregorianCalendar;
//抽象UserDAO:抽象主题角色
interface AbstractUserDAO {
public Boolean findUserById(String userId);
}
//抽象DocumentDAO:抽象主题角色
interface AbstractDocumentDAO {
public Boolean deleteDocumentById(String documentId);
}
//具体UserDAO类:真实主题角色
class UserDAO implements AbstractUserDAO {
public Boolean findUserById(String userId) {
if (userId.equalsIgnoreCase("张无忌")) {
System.out.println("查询ID为" + userId + "的用户信息成功!");
return true;
}
else {
System.out.println("查询ID为" + userId + "的用户信息失败!");
return false;
}
}
}
//具体DocumentDAO类:真实主题角色
class DocumentDAO implements AbstractDocumentDAO {
public Boolean deleteDocumentById(String documentId) {
if (documentId.equalsIgnoreCase("D001")) {
System.out.println("删除ID为" + documentId + "的文档信息成功!");
return true;
}
else {
System.out.println("删除ID为" + documentId + "的文档信息失败!");
return false;
}
}
}
//自定义请求处理程序类
class DAOLogHandler implements InvocationHandler {
private Calendar calendar;
private Object object;
public DAOLogHandler() {
}
//自定义有参构造函数,用于注入一个需要提供代理的真实主题对象
public DAOLogHandler(Object object) {
this.object = object;
}
//实现invoke()方法,调用在真实主题类中定义的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeInvoke();
Object result = method.invoke(object, args); //转发调用
afterInvoke();
return null;
}
//记录方法调用时间
public void beforeInvoke(){
calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
String time = hour + ":" + minute + ":" + second;
System.out.println("调用时间:" + time);
}
public void afterInvoke(){
System.out.println("方法调用结束!" );
}
}
编写如下客户端测试代码:
class Client {
public static void main(String args[]) {
InvocationHandler handler = null;
AbstractUserDAO userDAO = new UserDAO();
handler = new DAOLogHandler(userDAO);
AbstractUserDAO proxy = null;
//动态创建代理对象,用于代理一个AbstractUserDAO类型的真实主题对象
proxy = (AbstractUserDAO)Proxy.newProxyInstance(AbstractUserDAO. class.getClassLoader(), new Class[]{AbstractUserDAO.class}, handler);
proxy.findUserById("张无忌"); //调用代理对象的业务方法
System.out.println("------------------------------");
AbstractDocumentDAO docDAO = new DocumentDAO();
handler = new DAOLogHandler(docDAO);
AbstractDocumentDAO proxy_new = null;
//动态创建代理对象,用于代理一个AbstractDocumentDAO类型的真实主题对象
proxy_new = (AbstractDocumentDAO)Proxy.newProxyInstance(Abstract DocumentDAO.class.getClassLoader(), new Class[]{AbstractDocumentDAO.class}, handler);
proxy_new.deleteDocumentById("D002"); //调用代理对象的业务方法
}
}
编译并运行程序,输出结果如下:
调用时间:13:47:14 查询ID为张无忌的用户信息成功! 方法调用结束! ------------------------------ 调用时间:13:47:14 删除ID为D002的文档信息失败! 方法调用结束!
通过使用动态代理,我们可以实现对多个真实主题类的统一代理和集中控制。
注:JDK中提供的动态代理只能代理一个或多个接口,如果需要动态代理具体类或抽象类,可以使用CGLib(Code Generation Library)等工具,CGLib是一个功能较为强大、性能和质量也较好的代码生成包,在许多AOP框架中都得以广泛应用,大家可以自行查阅相关资料来学习CGLib。
# java动态代理的实现
# java
# 动态代理实现
# 动态代理实现原理
# 浅谈Java注解和动态代理
# 详解Java动态代理的实现及应用
# JAVA中的静态代理、动态代理以及CGLIB动态代理总结
# java 1.8 动态代理源码深度分析
# Java动态代理机制详解_动力节点Java学院整理
# java 中动态代理(JDK
# cglib)实例代码
# Java中反射动态代理接口的详解及实例
# Java 动态代理原理分析
# 多个
# 第一个
# 类中
# 张无忌
# 客户端
# 第二个
# 自定义
# 文档
# 第三个
# 是一个
# 表一
# 加载
# 是一种
# 集中控制
# 还可以
# 子类
# 它是
# 较好
# 要用
# 可以使用
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
重庆市网站制作公司,重庆招聘网站哪个好?
如何在IIS中新建站点并配置端口与物理路径?
Laravel如何实现密码重置功能_Laravel密码找回与重置流程
如何为不同团队 ID 动态生成多个“认领值班”按钮
如何正确下载安装西数主机建站助手?
Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理
PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑
php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】
详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南
如何批量查询域名的建站时间记录?
Laravel怎么实现验证码(Captcha)功能
java ZXing生成二维码及条码实例分享
如何快速搭建高效服务器建站系统?
JS经典正则表达式笔试题汇总
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
使用C语言编写圣诞表白程序
如何自定义建站之星模板颜色并下载新样式?
如何确保西部建站助手FTP传输的安全性?
微信推文制作网站有哪些,怎么做微信推文,急?
网站建设要注意的标准 促进网站用户好感度!
微信小程序 scroll-view组件实现列表页实例代码
Laravel如何实现事件和监听器?(Event & Listener实战)
如何在不使用负向后查找的情况下匹配特定条件前的换行符
湖南网站制作公司,湖南上善若水科技有限公司做什么的?
Laravel PHP版本要求一览_Laravel各版本环境要求对照
如何利用DOS批处理实现定时关机操作详解
Laravel如何实现用户密码重置功能?(完整流程代码)
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
如何快速搭建安全的FTP站点?
Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】
Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】
Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】
微信小程序 配置文件详细介绍
Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理
如何选择PHP开源工具快速搭建网站?
利用JavaScript实现拖拽改变元素大小
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
如何用wdcp快速搭建高效网站?
佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】
微信公众帐号开发教程之图文消息全攻略
JavaScript中如何操作剪贴板_ClipboardAPI怎么用
郑州企业网站制作公司,郑州招聘网站有哪些?
如何解决hover在ie6中的兼容性问题
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
微信小程序 wx.uploadFile无法上传解决办法

