SpringAOP实现的两种方式-JDK动态代理和CGLIB动态代理

news2024/9/30 17:24:50

前言

想要了解SpringAOP的实现方式,需要先了解什么是AOP

OOP和AOP的区别

  • OOP 面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

  • AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证.日志.事务处理。

AOP的核心

        AOP 实现的关键在于 代理模式,AOP 代理主要分为静态代理动态代理。静态代理的代表为 AspectJ;动态代理则以 Spring AOP 为代表

 什么是动态代理?

        Spring AOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP 中的动态代理主要有两种方式,JDK 动态代理CGLIB 动态代理

 JDK 动态代理

        JDK 动态代理只提供接口的代理,不支持类的代理。核心 InvocationHandler 接口和 Proxy 类,InvocationHandler 通过 invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

 CGLIB 动态代理

        如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。

 JDK 动态代理和 CGLIB 动态代理区别 

  • Spring默认使用JDK动态代理实现AOP代理,主要用于代理接口
  • CGLIB代理,实现类的代理,而不是接口

也就是说,JDK的动态代理是对接口的代理,而CGLIB的代理是对类的代理

 实例分析

JDK动态代理

我们创建一个电冰箱接口,和它的实现类,观察使用JDK代理和CGLIB代理的区别

FridgeBiz

public interface FridgeBiz {
    /**
     * 购买电冰箱
     * @param num
     */
    public void buy(int num,int stock);
}

FridgeBizImpl 

@Component(value = "fridgeBiz")
public class FridgeBizImpl implements FridgeBiz {

    private int stock;
    /**
     * 购买电冰箱
     *
     * @param num
     */
    @Override
    public void buy(int num,int stock) {
        this.stock=stock;
        System.out.println("顾客购买了"+num+"台电冰箱");
    }
}

 创建Aspect切面类:

LogAspect

@Aspect
@Component
public class LogAspect {
    @Pointcut("execution(void com.csx.service.impl.FridgeBizImpl.buy(int,int))")
    public void pt(){}

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        String methodName=  pjp.getSignature().getName();
        //获取请求方法的参数
        Object[] args = pjp.getArgs();
        System.out.println("电冰箱大折扣!,每人限购一台");
        try {
            return pjp.proceed();
        } finally {

            if ((Integer)args[1]<=(Integer) args[0]){
                System.out.println("电冰箱数量为"+args[1]+",电冰箱数量不足,请订购");
            }
            if ((Integer) args[0]!=1){
                System.out.println("顾客购买台数为"+args[0]+",超过1台,已限购");
            }

        }
    }

}

 配置spring.xml:

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <context:component-scan base-package="com.csx"/>
    <!--启用注解aop-->
    <aop:aspectj-autoproxy/>
</beans>	
	

在测试类中:

APPTest

在使用JDK的动态代理时,使用的是接口接收aop创建的代理对象

public class AppTest extends TestCase
{
 @Test
    public void testBefore(){
     ApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");
     FridgeBiz fridgeBiz =(FridgeBiz) context.getBean("fridgeBiz");
     fridgeBiz.buy(2,1);
//获取当前代理对象的全名
  System.out.println(fridgeBiz.getClass().getName());
 }
}

 查看结果:

CGLIB动态代理

如果想要使用CGLIB实现动态代理,根据以下步骤操作:

更新spring.xml:

spring.xml

设置 :

proxy-target-class="true"

 修改AppTest,使用实体类接收代理对象

public class AppTest extends TestCase
{
 @Test
    public void testBefore(){
     ApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");
//     FridgeBiz fridgeBiz =(FridgeBiz) context.getBean("fridgeBiz");
  FridgeBizImpl fridgeBiz =(FridgeBizImpl) context.getBean("fridgeBiz");
     fridgeBiz.buy(2,1);
  System.out.println(fridgeBiz.getClass().getName());
 }
}

出现结果:

总结

spring的动态代理主要有两种:

  • JDK 动态代理:生成接口的实现类对象
  • CGLIB 动态代理:生成实现类的子类对象

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

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

相关文章

让小脚本成为自己高效测试的工具

测试中会遇到的工具 软件测试如果仅仅靠手工去执行会发现在很多地方力不从心&#xff0c;虽然市面上已经有大牛开源了一些测试工具可以供我们使用但是在一些公司特有的业务方面则需要我们借助开源或重新做一个自己的测试工具。 测试常用的开源工具 死链接检测工具 Xenu home…

如何使用便签高效管理自己的工作和时间?

在快节奏的现代生活中&#xff0c;我们每天都要面对众多工作任务&#xff0c;而时间却是有限的。如何在有限的时间内高效地完成工作&#xff0c;成为了每个职场人士必须面对的挑战。为了更好地管理时间&#xff0c;提高工作效率&#xff0c;我们往往需要借助一些工具来帮助我们…

Linux上Java项目环境安装

java环境 一.免费的管理Linux软件 家庭/学校免费 - NetSarang Website (xshell.com) 二.安装jdk // 检查以前是否安装过jdk java -version // 我们还可以通过以下指令来看我们安装了多少openJDK apt list --installed | grep openjdk// 如果你想卸载某个apt安装的java版本&am…

CMOS Sensor调试笔记

最近在调CMOS Sensor&#xff1b;基于无ISP的芯片。 第一步&#xff0c;找模组厂要到对应Sensor对应分辨率&#xff0c;YUV信息的驱动。 第二步&#xff0c;确认信号的极性&#xff0c;VSYNC&#xff0c;SYNC, PCLK。 第三步&#xff0c;开始测试。 问题解决&#xff1a; 1&am…

覆盖生活中各方面的5款软件,非常好用

​ 在现代生活中&#xff0c;各类工具软件为我们提供了便捷的解决方案&#xff0c;从日程管理到系统优化&#xff0c;再到文件传输与多媒体编辑&#xff0c;各类软件的功能多样&#xff0c;极大地提升了我们的工作与生活效率。 1.日历清单——日历清单 ​ 日历清单是一款集日…

运营计划管理——电商运营(案例分享)

运营计划&#xff0c;作为运营管理的重要组成部分&#xff0c;通过科学规划与有效执行&#xff0c;对确保企业目标实现起着至关重要的作用。 运营计划是指通过制定、执行、监控和调整运营计划&#xff0c;以确保企业资源得到合理配置&#xff0c;业务活动有序进行&#xff0c;最…

学习threejs,添加户外光照光源

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言二、&#x1f340;绘制任意字体模型…

windows 桌面采集音频

头文件&#xff1a; #ifndef __CAPTURE_AUDIO__ #define __CAPTURE_AUDIO__#include <functional> #include <windows.h> #pragma comment(lib, "winmm.lib")class CaptureAudio { public:CaptureAudio();~CaptureAudio();public:bool Init(const std::…

云计算Openstack Glance

OpenStack Glance&#xff08;或称为Glance&#xff0c;但通常OpenStack官方文档中使用的是“Glance”作为项目代号&#xff09;是OpenStack的镜像服务组件&#xff0c;为创建虚拟机提供镜像服务。以下是对OpenStack Glance的详细解析&#xff1a; 一、基本功能 Glance主要提…

【HTML并不简单】笔记2-你不知道的a元素属性:target、download、ping、referrerpolicy和href

文章目录 target属性download属性ping属性referrerpolicyhref细节自动绝对地址锚点定位无障碍访问为何base元素无人问津实现链接元素a的嵌套 《HTML并不简单&#xff1a;Web前端开发精进秘籍》张鑫旭 笔记 target属性 有场景如下&#xff1a; 在线写作工具经常会有预览功能&a…

源2.0-M32大模型适配AutoGPTQ工具及量化推理教程

AutoGTPQ简介 AutoGPTQ‌是一个开源工具包&#xff0c;专注于简化大规模语言模型(LLMs)的量化过程。它基于高效的GPTQ算法开发&#xff0c;主要使用Python编程语言&#xff0c;并依托PyTorch框架来实现量化功能。AutoGPTQ的设计目标是为开发者和研究人员提供一个易于使用的API接…

【Golang】关于Go语言数学计算、随机数生成模块--math

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

多功能声学气膜馆:承载梦想与希望的舞台—轻空间

在9月29日上午&#xff0c;苏州大学应用技术学院的2024级新生开学典礼暨开学第一课在轻空间建造的多功能声学气膜馆内盛大举行。这一盛典不仅见证了2849名新生的入学&#xff0c;也展示了气膜馆的独特魅力与优越功能。 卓越的声学表现 声学气膜馆采用高性能材料&#xff0c;确保…

Linux-基础实操篇-组管理和权限管理(上)

Linux 组基本介绍 在 linux 中的每个用户必须属于一个组&#xff0c;不能独立于组外。在 linux 中每个文件 有所有者、所在组、其它组的概念。 用户和组的基本概念&#xff1a; 用户名&#xff1a;用来识别用户的名称&#xff0c;可以是字母、数字组成的字符串&#xff0…

解决DHCP服务异常导致设备无法获取IP地址的方法

DHCP在网络环境中会自动为网络中的设备分配IP地址和其他关键网络参数&#xff0c;可以简化网络配置过程。但是&#xff0c;如果DHCP服务出现异常时&#xff0c;设备可能无法正常获取IP地址&#xff0c;会影响到网络通信。 本文讲述一些办法可以有效解决DHCP服务异常导致设备无法…

YAML管理接口框架配置的最佳实践!!

YAML 文件在接口框架中作为配置管理的语言&#xff0c;以其简洁、直观的语法&#xff0c;迅速成为开发者的宠儿。然而&#xff0c;如何高效地管理和组织接口框架的配置&#xff0c;往往是一个容易被忽视的难题。你是否曾因为冗长的配置文件而感到头疼&#xff1f;今天&#xff…

干冰清洗机的工作原理

干冰清洗机的工作原理主要基于干冰的物理特性&#xff0c;特别是其升华过程。以下是干冰清洗机工作原理的详细解释&#xff1a; 一、干冰的制备 制冰系统&#xff1a;干冰清洗机内部配备有制冰系统&#xff0c;该系统将液态二氧化碳&#xff08;CO₂&#xff09;快速冷却并压…

HTTP协议讲解,请求报文与响应报文都是什么?网络控制台查看HTTP请求

目录 一. HTTP解析 二. 请求报文 2.1 请求行 2.1.1 请求类型 2.1.2 请求URL路径 2.1.3 发送的HTTP请求的版本 2.2 请求头 2.2.1 Host&#xff1a;主要用来实现虚拟主机技术 2.2.2 Cookie&#xff1a;一种让浏览器帮忙携带信息的手段 2.2.3 Content—type&#xff1a;…

揭秘分布式定时任务在人工智能RPA机器人中的应用|实在RPA研究

一、引言 在人工智能技术不断突破的今天&#xff0c;RPA智能机器人已经渗透到各行各业&#xff0c;成为企 业提升效率、降低成本的重要工具。而在机器人高效运作的背后&#xff0c;分布式定时任务发挥着 不可替代的作用。本文将深入探讨分布式定时任务在人工智能机器人中的应用…