前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解JDK动态代理

深入理解JDK动态代理

作者头像
windealli
发布于 2024-06-25 12:35:42
发布于 2024-06-25 12:35:42
31600
代码可运行
举报
文章被收录于专栏:windealliwindealli
运行总次数:0
代码可运行

一、什么是JDK动态代理

1. 什么是代理模式(Proxy Pattern)

代理模式是一种设计模式,它通过为其他对象提供一个代理或占位符来控制对原始对象的访问。即通过代理对象访问目标对象。

代理模式可以在不修改原始类代码的情况下,通过代理类,添加一些功能操作,比如添加方法调用的预处理、后处理等。

代理模式的基本概念包括以下几个部分:

  • 抽象对象(Subject): 这是一个接口,定义了代理对象和具体对象的公共接口,这样在任何使用具体对象的地方都可以使用代理对象。
  • 具体对象(RealSubject): 被代理的对象。 代理对象(Proxy): 包含了对具体对象的引用,从而可以在任何时候操作具体对象;代理对象提供了一个与具体对象相同的接口,所以它可以被当作具体对象使用。代理对象通常在客户端调用传递给实际对象之前或之后,执行某个操作,而不是只处理调用并将调用传递给实际对象。

Java中,代理模式的实现通常可以通过接口实现,但是也可以通过类或者抽象类实现。

2. 静态代理与动态代理

  • 静态代理 静态代理在编译时就已经实现,代码在编译时就已经确定,并已经被转换为字节码文件。
  • 动态代理 动态代理是在运行时动态生成的,即编译完成后还没有实际的代理对象,只有在运行时才会创建。

3. JDK动态代理

JDK动态代理是Java原生支持的代理方式,它允许开发者在运行时动态地创建和使用代理对象。这种方式主要依赖于Java的反射技术。

二、JDK动态代理的基本原理

1. JDK动态代理的工作原理

JDK动态代理的工作原理是在运行时在内存中动态地创建一个接口的实现类。

当我们通过代理类的对象调用方法时,它实际上会调用定义的InvocationHandler接口的实现类对象的invoke方法。然后在invoke方法中我们可以定义预处理、调用目标方法、后处理等,我们也可以选择不调用目标对象的方法。这样,我们就可以在不修改源码的情况下,实现对目标对象的功能增强。

2. JDK动态代理的关键组件:InvocationHandlerProxy

JDK动态代理主要涉及到java.lang.reflect包中的两个类:ProxyInvocationHandler。Proxy类是所有动态代理类的父类,它有一个名为newProxyInstance的方法,这个方法生成动态代理对象。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。

  • InvocationHandler:它是一个接口,我们必须实现该接口。我们可以通过实现该接口的invoke方法,定义横切逻辑,然后通过反射机制调用目标类的代码。动态的将横切逻辑和业务逻辑编织在一起。
  • ProxyProxy类是所有动态代理类的父类,它有一个名为newProxyInstance的方法,这个方法生成动态代理对象;newProxyInstance方法接收三个参数: 并返回一个新的代理对象(对象实现了指定的接口)。
    • ClassLoader loader(类加载器)、
    • Class<?>[] interfaces(给代理对象提供的接口)、
    • InvocationHandler h(调用处理器),

三、JDK动态代理的实现步骤

1. 定义一个接口和它的实现类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface MyInterface {
    void doSomething();
}

public class MyInterfaceImpl implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

2. 创建InvocationHandler对象,自定义invoke 方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method...");
        Object result = method.invoke(target, args);
        System.out.println("After method...");
        return result;
    }
}

3. 使用Proxy 类生成代理对象,并调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {
    public static void main(String[] args) {
        MyInterface myInterface = new MyInterfaceImpl();
        InvocationHandler handler = new MyInvocationHandler(myInterface);
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                myInterface.getClass().getClassLoader(),
                myInterface.getClass().getInterfaces(),
                handler);
        proxy.doSomething();
    }
}

运行以上代码,得到输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Before method...
Doing something...
After method...

四、JDK动态代理的实际应用

1. AOP(面向切面编程)中的应用

AOP是一种编程范式,其目标是提高程序模块化的程度。

在AOP中,切面(Aspect)是包含横切关注点实现的模块。切点(Pointcut)定义了在何处应用切面的代码逻辑。连接点(Joinpoint)是程序执行过程中的某个特定点,如方法调用或异常抛出。通知(Advice)是切面在特定连接点执行的动作。

JDK动态代理可以用于实现AOP中的通知。通过创建目标类的代理对象,我们可以在调用目标方法之前、之后或在抛出异常时插入自定义的逻辑。以下是一个简单的示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class LoggingAspect implements InvocationHandler {
    private Object target;

    public LoggingAspect(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

// 使用JDK动态代理创建代理对象
MyService myService = (MyService) Proxy.newProxyInstance(
        MyService.class.getClassLoader(),
        new Class<?>[]{MyService.class},
        new LoggingAspect(new MyServiceImpl()));

// 调用代理对象的方法
myService.doSomething();

2. Spring框架中的应用

动态代理在Spring框架中有广泛的应用,

  • Spring的AOP功能 就是基于动态代理实现的,当我们在Spring中配置一个bean为代理对象时,Spring会自动为这个bean创建一个代理对象。当我们调用bean的方法时,实际上是调用了代理对象的方法。这样,我们就可以在代理对象的方法中添加一些额外的逻辑,例如事务管理、日志记录等。
  • Spring的事务管理 也是通过动态代理实现的。当我们在方法上添加@Transactional注解时,Spring会为这个方法创建一个代理对象,用于在方法执行前后添加事务管理的代码。

在Spring中使用JDK动态代理时,我们需要定义一个切面(Aspect),并在切面中指定切点和通知。以下是一个简单的示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Aspect
public class LoggingAspect {
    @Before("execution(* com.example.MyService.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.MyService.*(..))")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }
}

// 在Spring配置类中启用AOP自动代理
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}

在这个示例中,我们使用了@Aspect注解来标记LoggingAspect类作为一个切面。@Before@After注解分别定义了前置通知和后置通知。execution表达式指定了切点,表示这些通知将应用于com.example.MyService类的所有方法。通过在Spring配置类中启用AOP自动代理,我们可以确保Spring会为匹配切点的方法创建代理对象,并应用相应的通知。

五、JDK动态代理的优缺点

1. 优点

  • 实现简单: JDK动态代理使用Java反射机制生成代理对象,不需要我们手动创建代理类。
  • 无嵌入性: 只需要实现InvocationHandler接口和创建代理类即可。对于简单的需求,这种方法是快速且易于实现的。
  • 动态性: JDK动态代理能够在运行时根据需要动态地创建代理对象,这为程序的扩展性和灵活性提供了支持。
  • **解耦:**通过代理模式,可以将目标对象与横切逻辑分离,降低了代码之间的耦合度,提高了代码的可维护性。
  • 跨平台: JDK动态代理是基于Java反射机制实现的,因此具有跨平台的特性。

2. 缺点

  • 性能开销: JDK动态代理使用反射机制来调用目标方法,这会导致一定程度的性能损失。尽管JVM对反射进行了优化,但在某些性能敏感的场景下,可能仍然不是最佳选择。
  • 仅支持接口代理: JDK动态代理只能为接口创建代理类,无法直接为类创建代理。这意味着如果目标对象没有实现任何接口,JDK动态代理将无法使用。
  • 代理类数量: 对于每个需要代理的接口,JDK动态代理都会生成一个新的代理类。如果有大量接口需要代理,这可能导致代理类数量过多,增加了部署和管理的复杂性。
  • 横切逻辑限制: JDK动态代理的横切逻辑必须实现为InvocationHandler接口的方法,这限制了横切逻辑的灵活性和多样性,无法处理复杂的情况。

六、CGLIB动态代理(拓展)

1. CGLIB动态代理的基本原理:

CGLIB(Code Generation Library)是一个开源项目,它提供了在运行时动态生成Java类的能力。CGLIB动态代理的基本原理是通过继承的方式进行代理。当我们对一个类进行CGLIB动态代理时,CGLIB会动态生成一个子类来继承这个类,然后在子类中添加我们的代理逻辑。当我们调用目标方法时,实际上是调用了子类的方法。因此,CGLIB动态代理可以代理任何类,不仅仅是接口。

2. JDK动态代理与CGLIB动态代理的比较:

  • JDK动态代理只能代理实现了接口的类,而CGLIB动态代理可以代理任何类。
  • JDK动态代理是通过反射机制实现的,而CGLIB动态代理是通过生成一个被代理类的子类来实现的。
  • 由于CGLIB动态代理生成的是子类,所以在性能上可能会比JDK动态代理稍微好一些,但是生成的类较多,可能会占用更多的内存。
  • 在Spring框架中,如果一个类没有实现接口,那么Spring会默认使用CGLIB进行动态代理。如果一个类实现了接口,Spring会优先使用JDK动态代理。如果要强制使用CGLIB,可以在Spring配置中进行设置。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海天二路搬砖工 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
TensorFlow 2.0 教程(1)
TensorFlow 2.0 终于发布了,看了介绍之后,发现越来越像Keras了。主要的变化在于:
用户7447819
2021/07/23
4750
Tensorflow2.0 教程-初识 TF2.0
TensorFlow 是谷歌基于 DistBelief 进行研发的第二代人工智能学习系统,自 2015 年问世,并在去年 11 月迎来三周岁生日,已经发展为世界上最受欢迎和被广泛采用的机器学习平台之一。
机器视觉CV
2019/07/14
2K0
tensorflow2.0学习1
一:tf安装 清华源安装tf2.0测试版 pip install tensorflow==2.0.0-alpha0 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package 二:测试 建立python文件(我这里是1.py) from __future__ import absolute_import, division, print_function import tensorflow as tf print(tf.__version__) 命令行
我是木木酱呀
2019/04/28
5760
【TensorFlow2.x开发—基础】 简介、安装、入门应用案例
本文介绍最新版本的TensorFlow开发与应用,目前最新版本是TensorFlow2.5.0;首先简单介绍一下TensorFlow,然后安装TensorFlow2,最后使用TensorFlow开发。
一颗小树x
2021/05/15
1.2K0
【TensorFlow2.x开发—基础】 简介、安装、入门应用案例
Tensorflow-1.9发布,提供Linux-Cuda9.1-cudnn7.1.2-whl安装包
看了下Tensorflow发布1.9版本已经10天了,Tensorflow更新着实快,这次更新还是值得我们去更新一下的。
老潘
2023/10/19
2420
Tensorflow-1.9发布,提供Linux-Cuda9.1-cudnn7.1.2-whl安装包
利用Tensorflow2.0实现手写数字识别
前面两节课我们已经简单了解了神经网络的前向传播和反向传播工作原理,并且尝试用numpy实现了第一个神经网络模型。手动实现(深度)神经网络模型听起来很牛逼,实际上却是一个费时费力的过程,特别是在神经网络层数很多的情况下,多达几十甚至上百层网络的时候我们就很难手动去实现了。这时候可能我们就需要更强大的深度学习框架来帮助我们快速实现深度神经网络模型,例如Tensorflow/Pytorch/Caffe等都是非常好的选择,而近期大热的keras是Tensorflow2.0版本中非常重要的高阶API,所以本节课老shi打算先给大家简单介绍下Tensorflow的基础知识,最后借助keras来实现一个非常经典的深度学习入门案例——手写数字识别。废话不多说,马上进入正题。
用户7569543
2020/07/19
1.1K0
利用Tensorflow2.0实现手写数字识别
【TensorFlow2.0】以后我们再也离不开Keras了?
在TensorFlow2.0中,Keras是一个用于构建和训练深度学习模型的高阶 API。因此如果你正在使用TensorFow2.0,那么使用Keras构建深度学习模型是您的不二选择。在Keras API中总共有如下三大块:
用户1508658
2019/07/28
1.3K0
【完结】TensorFlow2.0 快速上手手册
import tensorflow as tf a = tf.constant([1,2,3]) b = tf.constant([4,5,6]) print(a+b)
用户1508658
2019/07/25
3.9K0
【完结】TensorFlow2.0 快速上手手册
TensorFlow 2 quickstart for beginners
Load and prepare the MNIST dataset. Convert the samples from integers to floating-point numbers:
XianxinMao
2021/07/27
2920
Tensorflow日常随笔(一)
TensorFlow is an end-to-end open source platform for machine learning
XianxinMao
2021/07/31
2630
TensorFlow2.0(12):模型保存与序列化
模型训练好之后,我们就要想办法将其持久化保存下来,不然关机或者程序退出后模型就不复存在了。本文介绍两种持久化保存模型的方法:
Ai学习的老章
2019/12/30
1.8K0
Kubeflow Pipeline - 构建一个机器学习 Workflow
前面文章介绍过如何通过 Pipeline 来构建工作流,因为 Kubeflow 主要是在机器学习的场景下使用的,那么本文就简单介绍一下怎么构建一个简单 ML 的工作流。
runzhliu
2020/08/06
1.4K0
Kubeflow Pipeline - 构建一个机器学习 Workflow
TensorFlow高阶API和低阶API
TensorFlow提供了众多的API,简单地可以分类为高阶API和低阶API. API太多太乱也是TensorFlow被诟病的重点之一,可能因为Google的工程师太多了,社区太活跃了~当然后来Google也意识到这个问题,在TensorFlow 2.0中有了很大的改善。本文就简要介绍一下TensorFlow的高阶API和低阶API使用,提供推荐的使用方式。
用户7164815
2020/04/08
2.3K0
TensorFlow高阶API和低阶API
终版API已定型,TensorFlow 2.0 Beta蜕变归来
TensorFlow 发布以来,已经成为全世界最广泛使用的深度学习库。但 Tensorflow 1.x 时代最广受诟病的问题是:学习门槛较高、API 重复且复杂、模型部署和使用不够方便。之后,谷歌下定决心改变这一问题,在今年早些时候,发布了 Tensorflow 2.0 的 Alpha 版本。Alpha 版本一经问世,便受到深度学习研究者、开发者和在校学生的好评,其简洁的 API 和快速易上手的特性吸引了更多用户的加入。今天,Tensorflow 官方发布了 2.0 时代的 Beta 版本,标志着 Tensorflow 这一经典的代码库进一步成熟。
AI算法与图像处理
2019/06/14
7560
终版API已定型,TensorFlow 2.0 Beta蜕变归来
解决read_data_sets (from tensorflow.contrib.learn.python.learn.dat
最近在使用TensorFlow开发深度学习模型时,遇到了一个警告信息:​​read_data_sets (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version​​。经过查阅资料和尝试,我找到了解决这个问题的方法,下面我将分享给大家。
大盘鸡拌面
2023/10/20
4920
微信小程序|调用tensorflow自定义模型
在成功调用官网打包好的tensorflowjs模型后,怎么调用自己的模型呢?又需要做哪些处理呢?
算法与编程之美
2020/06/17
2.7K0
使用Python实现深度学习模型:分布式训练与模型并行化
随着深度学习模型的复杂度和数据量的增加,单一设备的计算能力往往无法满足训练需求。分布式训练和模型并行化技术可以有效地加速模型训练过程,提高计算效率。本文将介绍如何使用Python实现深度学习模型的分布式训练与模型并行化。
Echo_Wish
2024/07/09
2710
使用Python实现深度学习模型:分布式训练与模型并行化
TensorFlow bug激怒社区,用户:我要用PyTorch了!
issue 页面:https://github.com/tensorflow/tensorflow/issues/25175
机器之心
2019/04/30
9140
Tensorflow随笔(一)
In machine learning, to improve something you often need to be able to measure it. TensorBoard is a tool for providing the measurements and visualizations needed during the machine learning workflow. It enables tracking experiment metrics like loss and accuracy, visualizing the model graph, projecting embeddings to a lower dimensional space, and much more.
XianxinMao
2021/08/07
2620
TensorFlow2.0(9):神器级可视化工具TensorBoard
TensorBoard是TensorFlow中的又一神器级工具,想用户提供了模型可视化的功能。我们都知道,在构建神经网络模型时,只要模型开始训练,很多细节对外界来说都是不可见的,参数如何变化,准确率怎么样了,loss还在减小吗,这些问题都很难弄明白。但是,TensorBoard通过结合web应用为我们提供了这一功能,它将模型训练过程的细节以图表的形式通过浏览器可视化得展现在我们眼前,通过这种方式我们可以清晰感知weight、bias、accuracy的变化,把握训练的趋势。
Ai学习的老章
2019/12/25
3.7K0
相关推荐
TensorFlow 2.0 教程(1)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验