Spring5学习笔记—CGlib动态代理

news2024/11/24 15:34:33

在这里插入图片描述

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉
🍎个人主页:Leo的博客
💞当前专栏: Spring专栏
✨特色专栏: MySQL学习
🥭本文内容:Spring5学习笔记—CGlib动态代理
🖥️个人小站 :个人博客,欢迎大家访问
📚个人知识库: 知识库,欢迎大家访问

  • 学习参考 :

    • 讲师:孙帅老师
    • 课程:孙哥说Spring5

1.前言

前面文章我们学习了关于Spring的IOC与AOP相关知识点,在此之前,我们主要学习Spring的一些核心概念,IOCAOP等等。我们之前学习了简单了解了AOP如何借助动态字节码技术来构建动态代理类。实现动态代理的方式不止一种。本次系列文章主要介绍两种:JDK动态代理CGlib动态代理,主要主要介绍CGlib动态代理。好了,话不多说,让我们开始吧😎😎😎。

2.JDK动态代理有什么缺陷

在上一章关于JDK动态代理的讨论中,我们确实注意到了其一个明显的限制:原始类和代理类都必须实现同一个接口,代理类方法添加额外功能并调用原始类方法。这种方式就像房屋中介:他们为租客提供服务,而租客可能并不知道背后的真正房东。但这种模式确实存在局限性,特别是当我们的系统设计中没有采用接口,或者原始类并没有实现任何接口而是直接写具体方法实现时。

那么,面对这种情况,我们怎么办?我们如何实现动态代理而不受到必须实现接口这一限制的约束?为了解决这个问题,Cglib(Code Generation Library) 应运而生。Cglib为我们提供了一种不基于接口的代理实现方式,它可以直接代理类。相对于JDK的代理方式,Cglib是基于继承父类(原始类)的,它会动态生成一个子类来覆盖原始类的方法,从而实现代理功能。这样既可以保证二者方法一致,这样既可以保证在代理类中提供新的实现,同时又调用了原始方法

这种方法提供了更大的灵活性,特别是对于那些没有接口的类。在接下来的章节中,我们将深入探讨Cglib,了解它是如何提供这种强大功能的,以及它与JDK动态代理的区别和优缺点

3.什么是CGlib动态代理

CGLib**(Code Generation Library)**是一个强大的、高性能的代码生成库,它是基于Java字节码操作的开源框架。CGLib动态代理是CGLib框架提供的一种动态代理技术。与Java标准库中的动态代理(基于接口)不同,CGLib动态代理可以代理普通的类,而不仅限于接口。

使用CGLib动态代理,我们可以在运行时创建一个目标类的子类,并在子类中拦截并增强目标类的方法调用。这种方式不需要目标类实现任何接口,而是通过继承来实现代理。

CGLib动态代理的原理是通过生成目标类的子类来实现代理。在子类中,代理类重写了目标类的方法,并在方法中添加了额外的逻辑,例如前置处理、后置处理等。当我们调用代理对象的方法时,实际上是调用了子类中重写的方法,从而实现了对目标类方法的拦截和增强。

相比于基于接口的动态代理,CGLib动态代理的性能更高,但也因为需要生成子类,所以在代理类的创建过程中会消耗一定的时间和内存。因此,如果目标类已经实现了接口,且性能要求不高,那么使用基于接口的动态代理可能更合适;而如果目标类没有实现接口,或者对性能有较高要求,那么可以选择CGLib动态代理。

需要注意的是,CGLib动态代理只能代理非final的类,因为无法生成final类的子类。另外,由于CGLib动态代理是直接操作字节码的,所以在一些特殊的环境中可能会受到限制。

4.Spring5整合CGlib动态代理开发步骤

Spring框架提供了丰富的AOP功能,可以帮助我们更好地管理代码。在Spring中,我们可以使用CGlib动态代理来实现AOP功能。下面是一个简单的示例,演示如何使用Spring5整合CGlib动态代理。

  1. 原始类的设计:首先,我们要设计并定义一个原始类。特别要注意的是,这里的原始类无需实现任何接口。这为那些基于纯类设计而非接口设计的应用提供了方便。
  2. 定义增强功能:就像在JDK动态代理中一样,您需要确定您希望添加到原始类中的额外或增强功能。
  3. 生成动态代理对象:使用Cglib的Enhancer对象可以为上一步中定义的原始类生成动态代理对象。为了实现此过程,确保项目中包含了Cglib的必要依赖。幸运的是这些依赖已经包含在spring-context库中,从而简化了集成过程.

4.1创建目标对象

首先,我们需要创建一个目标对象,这个目标对象将被代理。在本例中,我们创建一个UserServiceImpl类作为目标对象,它包含一个addUser方法。

public class UserServiceImpl {
    public void addUser(String name) {
        System.out.println("添加用户:" + name);
    }
}

4.2创建切面类

接下来,我们需要创建一个切面类,这个切面类将在目标对象执行前或执行后执行一些操作。在本例中,我们创建一个LogAspect类作为切面类,它包含一个before方法,在目标对象执行前打印日志。

public class LogAspect {
    public void before() {
        System.out.println("开始执行方法...");
    }
}

4.3配置Spring AOP

1.配置文件方式

接下来,我们需要配置Spring AOP,以便在运行时生成代理对象。在本例中,我们使用XML配置文件来配置Spring AOP。

<bean id="userService" class="org.javatop.UserService">
    <property name="userServiceImpl" ref="userServiceImpl"/>
</bean>

<bean id="logAspect" class="org.javatop.LogAspect"/>

<aop:config>
    <aop:aspect ref="logAspect">
        <aop:before method="before" pointcut="execution(* org.javatop.UserServiceImpl.addUser(..))"/>
    </aop:aspect>
</aop:config>

在上面的配置中,我们首先创建了一个UserService类,并将其注入到UserServiceImpl类中。然后,我们创建了一个LogAspect类,并将其配置为切面类。最后,我们使用aop:before标签来定义一个切入点,指定在执行UserServiceImpl类的addUser方法之前执行LogAspect类的before方法。‘

2.原始方式
public class TestCglibProxy {

    private static final Logger log = LoggerFactory.getLogger(TestCglibProxy.class);

    @Test
    public void test1() {
        // 创建原始对象
        UserService userService = new UserService();

        // 创建Cglib提供的Enhancer对象,用于设置好创建代理对象
        Enhancer enhancer = new Enhancer();

        // 设置类加载器
        enhancer.setClassLoader(TestCglibProxy.class.getClassLoader());

        // 设置被代理类(原始父类)
        enhancer.setSuperclass(UserService.class);

        // 设置方法拦截器
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            // 等同于InvocationHandler中的invoke方法
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                log.debug("log before");

                Object ret = method.invoke(userService, objects);

                log.debug("log after");
                return ret;
            }
        };
        enhancer.setCallback(methodInterceptor);

        // 创建代理对象
        UserService userServiceProxy = (UserService) enhancer.create();
        userServiceProxy.login("Leo", "123456");
    }
}

4.4测试

最后,我们可以编写一个测试类来测试我们的代码。在本例中,我们创建一个Main类,通过Spring容器获取UserService对象,并调用其addUser方法。

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.addUser("Leo");
    }
}

当我们运行Test类时,我们可以看到在执行addUser方法之前打印了一条日志。

5.最后总结

JDK动态代理以接口为核心,通过Proxy.newInstance()方法为我们提供了创建代理对象的能力,要求原始类必须实现某个接口。而Cglib动态代理则更为灵活,不受接口的限制。通过Enhancer.create(),它直接生成原始类的子类,并在其中嵌入额外功能,从而实现代理。当然我们也可以通过设置让Spring在创建的时候只使用Cglib而不使用JDK

Spring AOP聪明地整合了这两种机制,为开发者提供了无缝的体验。它默认采用JDK动态代理,但当遇到没有实现接口的原始类时,会智能切换到Cglib动态代理。

本文介绍了如何使用Spring5整合CGlib动态代理实现AOP功能,并给出了具体的案例。通过使用动态代理,我们可以在运行时生成代理对象,从而实现对目标对象的增强。在实际开发中,动态代理是一个非常重要的概念,可以帮助我们更好地管理代码,提高代码的可维护性和可扩展性。

6.参考文献

  • https://www.itheima.com/news/20210525/165219.html
  • https://blog.csdn.net/luoyoub/article/details/80101376
  • https://spring.io/
  • https://blog.csdn.net/qq_43266723/article/details/133488696

7.总结

以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是Leo,一个在互联网行业的小白,立志成为更好的自己。

如果你想了解更多关于Leo,可以关注公众号-程序员Leo,后面文章会首先同步至公众号。

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

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

相关文章

Linux UWB Stack实现——FiRa会话状态机

在FiRa标准中&#xff0c;很重要的一个概念就是FiRa会话以及会话的管理&#xff0c;本文主要介绍了在Linux UWB Stack实现中&#xff0c;FiRa会话状态机管理的实现。 在FiRa中&#xff0c;会话分为INIT、DEINIT、ACTIVE、IDLE四种状态&#xff0c;其定义如下。 enum fira_sess…

2023年上半年上午易错题(软件设计师考试)

计算机中&#xff0c;系统总线用于 &#xff08;1&#xff09; 连接。 A. 接口和外设 B. 运算器、控制器和寄存器 C. CPU、主存及外设部件 D. DMA控制器和中断控制器 在由高速缓存、主存和硬盘构成的三级存储体系中&#xff0c;CPU执行指令时需要读取数据&#xff0c;那…

常用JQuery插件汇总

Jquery插件&#xff0c;数字动画特效&#xff0c;从n到m数字跳动JJ​​​​​​​CountUp.jsA javascript class that animates a numerical value by counting to it.http://inorganik.github.io/countUp.js/

pycharm 2023.2.3设置conda虚拟环境

分两步&#xff1a; &#xff08;1&#xff09;设置Virtualenv Environment &#xff08;2&#xff09;设值Conda Executable 加载conda环境&#xff0c;然后选择conda环境

系列二十三、bean的创建顺序是由什么决定的

一、bean的创建顺序是由什么决定的 bean的创建顺序是由bean的注册顺序决定的。 # 第一步&#xff1a; AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(MySpringConfig.class);# 第二步&#xff1a; refresh();# 第三步&#xff1a; fi…

绿色先行——建行江门市分行支助力补齐“三农”金融服务短板

7月的台山&#xff0c;稻谷飘香。在大耕户李胜业的农田里&#xff0c;金灿灿的稻谷翻起层层稻浪&#xff0c;收割机在稻浪里来回穿梭&#xff0c;割稻、脱粒、装车等工序一气呵成。空气中弥漫着丰收的喜悦。 夏粮迎丰收的背后&#xff0c;是中国建设银行江门市分行&#xff08;…

【计算机网络】(谢希仁第八版)第一章课后习题答案

1.计算机网络可以向用户提供哪些服务&#xff1f; 答&#xff1a;例如音频&#xff0c;视频&#xff0c;游戏等&#xff0c;但本质是提供连通性和共享这两个功能。 连通性&#xff1a;计算机网络使上网用户之间可以交换信息&#xff0c;好像这些用户的计算机都可以彼此直接连…

【机器学习可解释性】4.SHAP 值

机器学习可解释性 1.模型洞察的价值2.特征重要性排列3.部分依赖图4.SHAP 值5.SHAP 值 高级使用 正文 理解各自特征的预测结果&#xff1f; 介绍 您已经看到(并使用)了从机器学习模型中提取一般解释技术。但是&#xff0c;如果你想要打破模型对单个预测的工作原理? SHAP 值…

第三章 SysML入门|系统建模语言SysML实用指南学习

仅供个人学习记录 UML与SysML的联系 可以稍微参考UML与SysML的联系 UML&#xff08;统一建模语言&#xff09;和SysML&#xff08;系统建模语言&#xff09;是两种与建模相关的语言&#xff0c;它们之间存在联系和区别。 SysML的图分类如下图所示。 SysML 图概述 这里只…

GZ035 5G组网与运维赛题第3套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第3套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; 子…

锐捷smartWeb管理系统存在逻辑缺陷漏洞

通过弱口令进行登录 guest/guest 通过低权限用户构造payload&#xff1a; /web/xml/webuser-auth.xml访问漏洞url&#xff0c;直接获得所有账户的等级标志和base64加密的账号密码&#xff0c;解秘后即可登录后台 解密管理员的账号密码 成功登录 文笔生疏&#xff0c;措辞浅…

C++快餐——C++11(1)

文章目录 背景简介统一列表初始化{}初始化initializer_lists初始化 关键字autodecltypenullptr 范围for右值引用和移动语义左值和右值左值引用和右值引用完美转发 默认成员函数总结 背景简介 C11&#xff0c;也被称为C0x&#xff08;在它被正式标准化之前的名字&#xff09;&a…

JVM调优(10)JVM的运行时数据区

一、概述 对于 C C 来说&#xff0c;在内存管理领域&#xff0c;JVM既拥有最高的权利&#xff0c;但是同时他们又是从事最基础工作的劳动人员&#xff0c;因为他们担负着每一个对象从开始到结束的维护责任。而对于Java来说&#xff0c;再虚拟机自动内存管理的帮助下&#xff0…

Proteus仿真--花样流水灯(仿真文件+程序)

本文主要介绍基于51单片机的花样流水灯仿真&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真运行视频 Proteus仿真--花样流水灯&#xff08;仿真文件程序&#xff09; 附完整Proteus仿真资料代码资料 链接: https://pan.baidu.com/s/1coEEBQcTQSzWQiSH_nNiUQ?pw…

vm虚拟机保护技术简介EzMachine例题-vm逆向分析

文章目录 前言0x1 虚拟机保护技术原理0x1A 关于调用约定0x1B Handler0x1C 指令 0x2 vm虚拟机逆向 实战[GKCTF 2020]EzMachine题目分析&#xff0c;花指令去除Handler分析脚本编写 前言 关于虚拟机逆向的知识网上很少&#xff0c;我看了几篇感觉都看不太明白&#xff0c;最后还…

如何设置3D模型的凹凸贴图?

1、凹凸贴图的原理&#xff1f; 凹凸贴图&#xff08;bump mapping&#xff09;是一种计算机图形技术&#xff0c;用于增强表面的视觉效果&#xff0c;使其看起来具有凹凸感&#xff0c;而实际上并没有改变模型的几何形状。 凹凸贴图的原理基于光照模型。通常&#xff0c;我们…

分布式理论和分布式锁知识点总结

文章目录 (一) 分布式理论算法和协议1&#xff09;CAP理论总结 2&#xff09;BASE理论BASE 理论的核心思想基本可用软状态最终一致性 3&#xff09;Paxos算法Basic Paxos 算法4&#xff09; Raft算法1 拜占庭将军 5&#xff09;Gossip协议 (二) 分布式锁分布式锁应该具备哪些条…

U盘RAW格式怎么恢复 U盘RAW格式怎么改过来

当我们遇到U盘变成raw格式时&#xff0c;首先需要了解的是&#xff0c;U盘的raw格式通常是由于文件系统损坏或病毒感染引起的。当U盘变成raw格式时&#xff0c;将导致无法正常访问其中数据。因此&#xff0c;需要我们手动恢复U盘中的相关数据&#xff0c;那么下面就来为大家介绍…

亚信科技:发挥自我优势深入AIGC,并购整合高瞻远瞩致力未来路

【科技明说 &#xff5c; 重磅专题】 亚信科技在IT提供商领域中是一个低调的前行者&#xff0c;在全球通信及大型企业市场中扮演着重要的角色。对于近年来如火如荼AI方面的投入与研究&#xff0c;亚信科技是否也很重视呢&#xff1f; 事实上&#xff0c;是肯定的回答。 在我看…

C++ stack queue 的模拟实现

1.为什么选择 deque 作为 stack 和 queue 的默认容器呢&#xff1f; stack 是一种后进先出的特殊线性数据结构&#xff0c;因此只要具有 push_back() 和 pop_back() 操作的线性结构&#xff0c;都可 以作为 stack 的底层容器&#xff0c;比如 vector 和 list 都可以&#xff1b…