Spring代理方式之静态、动态代理(JDK和CGlib动态代理)

目录

1、代理设计模式的概念

2、静态代理

3、动态代理(JDK和CGlib动态代理)

1. JDK动态代理是基于接口的代理(Interface-based proxy)

2. CGLIB代理是基于类的代理(Class-based proxy)

⭐比较:JDK动态代理和CGLIB代理的区别

4、代理设计模式的目的和作用

小结


1、代理设计模式的概念

在Spring框架中,代理设计模式主要是将核心功能与辅助功能(事务、日志、性能监控代码)分离,达到核心业务功能更纯粹、辅助业务功能可复用的目标。Spring框架利用代理模式来实现AOP(Aspect-Oriented Programming),通过代理对象对目标对象的方法调用进行拦截和增强,以实现横切关注点的功能。为此,spring中的代理方式可以分为静态代理和动态代理,而动态代理中又包含基于接口的JDK动态代理和基于类的CGLIB代理

P.S. 关于AOP的相关知识点本文不做详细介绍,后面会单独写一篇介绍。

图片来源:《Spring》

2、静态代理

在Spring中,静态代理是一种代理设计模式的实现方式。它通过手动编写代理类来对目标对象进行代理,并在代理类中调用目标对象的方法。

具体来说,静态代理需要满足以下条件:

  1. 定义一个接口(或者父类),该接口包含了目标对象和代理对象共同的方法。
  2. 创建一个代理类,实现上述接口,并持有一个目标对象的引用。
  3. 在代理类的方法中,可以在目标对象的方法调用前后加入额外的处理逻辑,比如日志记录、权限控制等。
  4. 在使用时,通过创建代理对象来替代直接使用目标对象,从而实现对目标对象方法的代理。

相对于动态代理,静态代理的主要特点是代理类在编译期间就已经存在,代理类在创建时,接口以及代理类就已经确定,因此称为静态代理。静态代理的优点是简单、直观,易于理解和实现。但是缺点也比较明显,每个目标对象都需要对应一个代理类,如果目标对象的方法发生变化,代理类也需要相应地做出修改。

值得注意的是,在Spring框架中,通常更多地使用动态代理来实现AOP的功能,因为动态代理可以更灵活地生成代理对象,避免了频繁编写和维护代理类的问题。但是了解静态代理的工作原理仍然是有益的,可以更好地理解AOP的实现原理。

通过代理类的对象,为原始类的对象(目标类的对象)添加辅助功能,更容易更换代理实现类、利 于维护。

图片来源:《Spring》

代理类 = 实现原始类相同接口 + 添加辅助功能 + 调用原始类的业务方法。

静态代理的问题:代理类数量过多,不利于项目的管理。 多个代理类的辅助功能代码冗余,修改时,维护性差。

3、动态代理(JDK和CGlib动态代理)

1. JDK动态代理是基于接口的代理(Interface-based proxy)

它要求被代理的目标对象必须实现一个或多个接口。JDK动态代理通过反射机制在运行时创建一个代理对象,代理对象实现了目标对象相同的接口,并且可以通过代理对象调用目标对象的方法。基于接口的代理要求目标对象必须实现接口,只能代理接口中定义的方法。

JDK动态代理的优点是代理对象的创建和使用都比较简单,缺点是只能代理实现了接口的目标对象。

下面是代码示例:

首先,定义一个接口,并创建实现类

public interface IUserService {
    void addUser(String username, String password);
}
public class UserService implements IUserService {
    @Override
    public void addUser(String username, String password) {
        System.out.println("Add user: " + username + ", " + password);
    }
}

然后,使用JDK动态代理来生成代理对象。JDK动态代理需要目标对象实现一个接口,它利用Java反射机制在运行时动态地生成代理类。下面是JDK动态代理的实现代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkDynamicProxyExample {
    public static void main(String[] args) {
        IUserService target = new UserService(); // 创建目标对象

        // 创建JDK动态代理
        IUserService proxy = (IUserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), // 目标对象的类加载器
                target.getClass().getInterfaces(),  // 目标对象实现的接口
                new InvocationHandler() {           // 代理对象的调用处理程序
                    @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;
                    }
                }
        );

        // 调用代理对象的方法
        proxy.addUser("Alice", "123456");
    }
}

运行上述代码,输出结果为:

Before method: addUser
Add user: Alice, 123456
After method: addUser

可以看到,在JDK动态代理中,通过InvocationHandler来实现代理对象的调用处理程序。在调用代理对象的方法时,实际上是通过反射机制调用目标对象的方法,并在方法调用前后加入了额外的处理逻辑。

2. CGLIB代理是基于类的代理(Class-based proxy)

它可以代理没有实现接口的目标对象。CGLIB(Code Generation Library)是一个强大的第三方类库,其代理通过继承目标对象并重写其中的方法来实现代理,因此它的代理对象是目标对象的子类。当目标对象没有实现任何接口时,Spring会使用CGLIB来创建代理对象。CGLIB会生成目标对象的子类,并拦截目标对象的方法调用。基于类的代理可以代理目标对象的所有方法,包括非公开方法和静态方法。

CGLIB代理的优点是可以代理没有实现接口的目标对象,缺点是代理对象的创建和使用比较复杂。

接下来,使用CGlib动态代理来生成代理对象。CGlib动态代理不需要目标对象实现一个接口,它利用ASM框架在运行时动态地生成代理类。下面是CGlib动态代理的实现代码:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGlibDynamicProxyExample {
    public static void main(String[] args) {
        UserService target = new UserService(); // 创建目标对象

        // 创建CGlib动态代理
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("Before method: " + method.getName());
                Object result = proxy.invokeSuper(obj, args); // 调用目标对象的方法
                System.out.println("After method: " + method.getName());
                return result;
            }
        });
        UserService proxy = (UserService) enhancer.create();

        // 调用代理对象的方法
        proxy.addUser("Bob", "654321");
    }
}

运行上述代码,输出结果为:

Before method: addUser
Add user: Bob, 654321
After method: addUser

可以看到,在CGlib动态代理中,通过MethodInterceptor来实现代理对象的调用处理程序。在调用代理对象的方法时,实际上是通过MethodProxy调用目标对象的方法,并在方法调用前后加入了额外的处理逻辑。

Spring框架在选择代理方式时遵循以下规则:

  • 如果目标对象实现了至少一个接口,则默认使用基于接口的代理(jdk)。
  • 如果目标对象没有实现任何接口,则使用基于类的代理(cglib)。

可以通过配置Spring的AOP相关选项来控制代理方式。例如,可以使用<aop:config>元素来声明切面和通知,并通过proxy-target-class属性来指定是否使用基于类的代理(默认为false)。

需要注意的是,基于接口的代理要求目标对象实现接口,而基于类的代理则可以代理任何类型的对象。但是,由于基于类的代理需要生成子类,因此在创建代理对象时可能会引入一些性能开销。

⭐比较:JDK动态代理和CGLIB代理的区别

1.实现方式不同:JDK动态代理是基于接口实现的,它要求被代理类必须实现一个接口,代理类实现了这个接口并且调用被代理类的方法;而CGLIB动态代理是基于继承实现的,它可以代理没有实现接口的类,它通过生成被代理类的子类来实现代理。

2.性能不同:JDK动态代理是通过反射来调用被代理类的方法,因此它的性能比CGLIB动态代理要差一些;而CGLIB动态代理是通过生成字节码来调用被代理类的方法,因此它的性能比JDK动态代理要好一些。

3.适用场景不同:JDK动态代理适用于代理接口的情况,它可以为多个接口创建代理对象,而CGLIB动态代理适用于代理类的情况,它可以为单个类创建代理对象。

4、代理设计模式的目的和作用

代理设计模式的主要目的是在不改变原有类结构的情况下,为类的功能增加一些额外的处理逻辑。在Spring中,代理设计模式的作用主要包括以下几点:

  1. 实现横切关注点(Cross-Cutting Concerns): 通过代理模式,可以将与核心业务逻辑无关的功能,如日志记录、事务管理、安全性控制等,抽取出来形成独立的横切关注点,并在需要的时候将其应用到目标对象的方法调用中。这样可以使得关注点的代码得以重用,并且更容易实现集中管理。

  2. 解耦关注点和核心业务逻辑: 代理模式可以帮助将横切关注点与核心业务逻辑进行解耦。通过代理对象对方法调用的拦截和增强,可以将横切关注点的实现与核心业务逻辑分离开来,使得各部分之间的耦合度降低,提高了代码的可维护性和可扩展性。

  3. 实现通用性和复用性: 代理模式可以使得一些通用的横切关注点的实现得以复用,而不需要在每个类中都编写重复的代码。通过定义通用的拦截器或增强逻辑,在需要的时候将其应用到多个类的方法调用中,从而实现代码的通用性和复用性。

  4. 实现动态代理: 代理模式还可以实现动态代理,即在运行时动态地创建代理对象,根据需要在目标对象的方法调用前后插入额外的处理逻辑。这种动态代理的方式使得可以更加灵活地控制代理对象的行为,同时也为AOP的实现提供了基础。

小结

总之,Spring框架中的代理设计模式旨在通过代理对象对目标对象的方法调用进行拦截和增强,以实现横切关注点的功能,同时提高代码的可维护性和可扩展性。Spring动态代理提供了JDK动态代理和CGlib动态代理两种实现方式。它们都可以利用AOP技术来实现横切关注点的功能,但是具体的实现方式有所差异。在使用时需要根据实际情况选择合适的代理方式。

参考:

JDK动态代理和CGLIB动态代理_梵晞的博客-CSDN博客

Spring代理模式 - 風栖祈鸢 - 博客园

JAVA高级基础:Spring中AOP的两种代理方式动态代理和CGLIB详解_aop代理的两种方式-CSDN博客

Spring(2)——代理和AOP - 知乎

详解Spring的两种代理方式:JDK动态代理和CGLIB动态代理 - 编程语言 - 亿速云

Spring_代理模式 - 只会干饭的杜某 - 博客园


感谢阅读,码字不易,多谢点赞!如有不当之处,欢迎反馈指出,感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/199512.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

embeddings

“embeddings”的中文翻译是“嵌入”或“嵌入向量”。在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;通常被称为“词向量”或“词嵌入”&#xff0c;它是表示词汇或令牌的一种方式&#xff0c;通过将这些词汇或令牌映射到一个向量空间中的点&#xff0c;以捕捉它们…

Gin投票系统(2)

投票系统 数据库的建立 先分析需求&#xff0c;在sql中建立数据库&#xff0c;关于项目数据库如何建立可以在“goweb项目创建流程分析中看如何去建表” 成功后目前有四个表&#xff1a; vote&#xff0c;user&#xff0c;vote_opt,vote_opt_user 建立数据库&#xff0c;可以…

Web学习笔记

Web学习笔记 flask库前端基础超链接&#xff1a;空连接&#xff1a;图片&#xff1a;视频&#xff08;音频&#xff09;&#xff1a;嵌套使用列表表格格式化表格input表单系列 网络请求GET方式POST请求通过GET方式获取输入参数通过POST方式获取输入参数注册页面 CSS三种使用方式…

超卓航科聚国内外专家学者,共推冷喷涂技术的发展与应用

11月24日——26日&#xff0c;冷喷涂技术及其在增材制造中的应用专题会在襄阳召开&#xff0c;来自国内外200多名科技工作者齐聚一堂&#xff0c;共同交流冷喷涂技术的研究与应用。 本次专题研讨会由中国机械工程学会表面工程分会主办&#xff0c;湖北超卓航空科技股份有限公司…

C语言第三十六弹--实现转移表的多种方法

使用C语言通过多种方法实现转移表 方法一、普通法 思路&#xff1a;如图实现多种操作&#xff0c;首先创建菜单&#xff0c;需要运行一次再判断条件&#xff0c;所以通过do{}while(); 循环来实现多次。有多种选择&#xff0c;使用switch case选择语句&#xff0c;再在对应case…

Spark---SparkCore(五)

五、Spark Shuffle文件寻址 1、Shuffle文件寻址 1&#xff09;、MapOutputTracker MapOutputTracker是Spark架构中的一个模块&#xff0c;是一个主从架构。管理磁盘小文件的地址。 MapOutputTrackerMaster是主对象&#xff0c;存在于Driver中。MapOutputTrackerWorker是从对…

Leetcode—2336.无限集中的最小数字【中等】

2023每日刷题&#xff08;四十四&#xff09; Leetcode—2336.无限集中的最小数字 实现代码 class SmallestInfiniteSet {set<int> s; public:SmallestInfiniteSet() {for(int i 1; i < 1000; i) {s.insert(i);}}int popSmallest() {int res *s.begin();s.erase(s…

【区块链】产品经理的NFT初探

常见的FT如比特币&#xff08;BTC&#xff09;&#xff0c;以太币&#xff08;ETH&#xff09;等&#xff0c;两个代币之间是完全可替换的。而NFT具有唯一性&#xff0c;不可以互相替换。本文作者对NET的发展现状、相关协议、应用场景等方面进行了分析&#xff0c;一起来看一下…

深度解读:为什么要做数据合规?如何做到数据合规?

数据资源“入表”在即&#xff0c;企业更需筑牢数据合规防线。但企业主企业购买数据、获取数据到底是否合法合规&#xff0c;入表如何防范合规风险&#xff1f;上周三&#xff0c;亿信华辰邀请到北京鑫诺律师事务所高级合伙人、管委会副主任武婕将和大家分享《数据入表法律合规…

ReactDomServer 将react组件转化成html静态标签(SSR服务器渲染)

前言&#xff1a; 因为使用图表里面的formatter函数需要原生的html标签&#xff0c;但是本身技术栈是react&#xff0c;所以为了方便&#xff0c;便使用了ReactDomServer api将react组件转化成html原生标签引入&#xff1a; import ReactDomServer from react-dom/server; 使…

Debian10安装VMware Tools

一、原系统 首先我在界面按CTRLALTT和CTRLSiftT都没有反应&#xff0c;没关系&#xff0c;我有办法 系统版本 管理员用户 步骤一&#xff1a;打开VMware Tools文件 步骤二、将文件复制到自己熟悉的文件内 步骤三、命令行查看文件是否复制成功存在 步骤四、解压VMware-tools…

MIT线性代数笔记-第17讲-正交矩阵,Schmidt正交化

目录 17.正交矩阵&#xff0c; S c h m i d t Schmidt Schmidt正交化打赏 17.正交矩阵&#xff0c; S c h m i d t Schmidt Schmidt正交化 “标准”经常表示单位长度 标准正交基&#xff1a;由两两正交的单位向量组成的基 将标准正交基中的元素记作 q ⃗ 1 , q ⃗ 2 , ⋯ , q …

Redis学习文档

目录 一、概念1、特征2、关系型数据库和非关系型数据库的区别3、键的结构4、Redis的Java客户端5、缓存更新策略5.1、概念5.2、代码 6、缓存穿透6.1、含义6.2、解决办法6.3、缓存空值代码举例6.4、布隆过滤器代码举例 7、缓存击穿7.1、概念7.2、解决办法7.3、互斥锁代码举例7.4、…

DBT踩坑第二弹

总结下dbt-spark踩到的坑&#xff0c;连接方式采用的是thrift连接 Kerberos认证。考虑到开源组件Kyuubi也是基于Hiveserver2&#xff0c;使用的thrift协议&#xff0c;所以采用Kyuubi执行SparkSQL。 官方文档给出的Thrift方式连接示例真的是简单&#xff0c;但是真是用起来真是…

vue3 + element-plus + ts el-table封装

vue3 element-plus ts el-table封装 博客参考https://blog.csdn.net/weixin_45291937/article/details/125523244 1. 文件位置&#xff08;根据自己的需求&#xff09; 2. 在 custom 文件夹下面 创建 mytable 文件夹 3. 直接上代码 // index.vue<template><div …

西工大网络空间安全学院计算机系统基础实验一(123)

在实验零中&#xff0c;我们拿到了lab1-handout.zip压缩文件&#xff0c;接着&#xff0c;我们使用unzip ./lab1-handout.zip命令&#xff0c;解压缩该压缩文件。解压缩成功后&#xff0c;使用"ls"命令查看当前工作目录下的文件和文件夹&#xff0c;发现得到了"…

Day41 使用listwidget制作简易图片播放器

1.简介 使用QlistWidget实现简易图片播放器&#xff0c;可以打开一个图片序列&#xff0c;通过item的单击事件实现图片的切换&#xff0c;通过设置list的各种属性实现图片预览的显示&#xff0c;美化滚动条即可实现一个简易图片播放器。 2.效果 3.实现步骤&#xff1a; 1.初始…

如何使用 Python(NumPy 和 OpenCV)对图像进行 Funkify

如何使用 Python&#xff08;NumPy 和 OpenCV&#xff09;对图像进行 Funkify 作者|Luke Tambakis 编译|Flin 来源|medium 在这篇博客中&#xff0c;我将解释如何制作一个 Python 脚本来使用 Python 代码“funkify”图像。该程序速度足够快&#xff0c;甚至可以处理实时视频&am…

【Java Spring】Spring MVC基础

文章目录 1、Spring MVC 简介2、Spring MVC 功能1.1 Spring MVC 连接功能2.2 Spring MVC 获取参数2.2.1 获取变量2.2.2 获取对象2.2.3 RequestParam重命名后端参数2.2.4 RequestBody 接收Json对象2.2.5 PathVariable从URL中获取参数 1、Spring MVC 简介 Spring Web MVC是构建于…

低压三相无刷直流驱动芯片GC5958,无感,正弦,低压,PWM调速可替代APX9358/茂达

GC5958提供了无传感器的三相无刷直流电机的速度控制的所有电路。正弦波驱动器的方法将是更好的低噪声。控制器功能包括启动电路、反电动势换向控制、脉宽调制 (PWM) 速度控制锁定保护和热关断电路GC5958适用于需要静音驱动程序的游戏机和CPU散热器。它以DFN3x3-10封装形式展现。…