SpringAOP源码解析之TargetSource(四)
前言
在Spring框架中,TargetSource是一个接口,用于封装获取目标对象(也就是被代理的对象)的逻辑。它的主要作用是提供代理对象使用的目标对象,并且允许在运行时动态地切换目标对象。TargetSource在Spring的AOP(面向切面编程)中非常重要,它定义了代理对象的目标是谁以及在何时获取目标对象。
具体来说,TargetSource接口定义了以下两个方法:
-
getTarget():这个方法用于获取目标对象。AOP代理对象在执行方法时,会先调用getTarget()方法获取目标对象,然后再在目标对象上执行相应的方法。
-
releaseTarget(Object target):这个方法用于释放目标对象。在一些特殊的场景中,可能需要手动释放目标对象,以便它可以被垃圾回收或者被缓存起来以供下次使用。
-
isStatic() 方法:该方法用于指示目标对象是否是静态的。如果目标对象是静态的,那么TargetSource可以在代理创建时确定代理对象的类型,从而进行更好的性能优化。如果目标对象是动态的(例如在运行时根据条件切换不同的实例),则返回false。
-
getTargetClass() 方法: 该方法返回代理的目标对象的类类型。在使用基于接口的代理(例如JDK动态代理)时,这个方法返回接口的类型。在使用基于类的代理(例如CGLIB代理)时,这个方法返回目标对象的类型。这个信息通常用于确定代理的类型。
TargetSource的作用体现在以下几个方面:
-
AOP代理: 在AOP中,TargetSource允许你控制代理对象的目标对象是谁。例如,你可以创建一个TargetSource实现,根据特定条件选择不同的目标对象。这种灵活性使得你能够动态地选择在代理对象上应用哪些切面逻辑。
-
性能优化: 通过TargetSource,你可以实现一些性能优化的技术,比如对象池(Object Pooling)。你可以将对象缓存起来,而不是每次都创建新的对象,从而减少了对象的创建和销毁开销。
-
多数据源切换: 在一些应用中,可能需要根据不同的请求选择不同的数据源。通过自定义的TargetSource,你可以根据请求动态切换目标数据库。
-
状态管理和缓存: TargetSource可以用于状态管理和缓存策略。你可以在getTarget()方法中加入状态管理逻辑,确保每次获取到的目标对象都是处于特定状态的。同时,也可以在这里实现缓存逻辑,将经常使用的对象缓存起来,提高系统性能。
官方TargetSource地址
Spring中TargetSource的默认实现
PrototypeTargetSource、SingletonTargetSource、SimpleBeanTargetSource、ThreadLocalTargetSource 和 CommonsPool2TargetSource 都是 Spring 框架中的 TargetSource 实现,它们分别适用于不同的场景,具有不同的特点和用途。
1. PrototypeTargetSource:
- 作用: PrototypeTargetSource 用于原型(prototype)的 Bean,每次请求时都会创建一个新的实例。
- 特点: 适用于需要在每次请求时都创建新实例的目标对象,保持状态隔离。
2. SingletonTargetSource:
- 作用: SingletonTargetSource 用于单例的 Bean,整个应用程序生命周期内只有一个实例。
- 特点: 适用于状态无关的、可共享的目标对象。
3. SimpleBeanTargetSource:
- 作用: SimpleBeanTargetSource 用于简单的 Bean 对象,通常是指那些没有接口或者特殊要求的类。
- 特点: 将普通的 Java 对象转化为 Spring AOP 可以处理的代理对象。
4. ThreadLocalTargetSource:
- 作用: ThreadLocalTargetSource 将目标对象保存在 ThreadLocal 中,使得每个线程都有自己的目标对象实例。
- 特点: 适用于多线程环境下,每个线程都拥有独立的目标对象实例。
5. CommonsPool2TargetSource:
- 作用: CommonsPool2TargetSource 使用 Apache Commons Pool 2 来管理目标对象的池化。
- 特点: 可以灵活地控制对象池的大小和行为,适用于需要对象池管理的场景。
区别和使用场景总结:
-
PrototypeTargetSource 和 SingletonTargetSource 分别适用于需要每次请求都创建新实例和整个应用程序生命周期内共享同一个实例的场景。
-
SimpleBeanTargetSource 适用于没有接口和特殊要求的普通 Java 对象。
-
ThreadLocalTargetSource 适用于多线程环境,需要每个线程都有独立目标对象实例的场景。
-
CommonsPool2TargetSource 适用于需要对象池管理的场景,可以灵活地控制对象池的行为,比如最大池大小、最小池大小等。
普通的 AOP 代理创建使用的 TargetSource
日常工作中使用Spring AOP 代理 bean 基本都会走 AutoProxyCreator#wrapIfNecessary() 来进行创建。
它使用的 TargetSource 是 SingletonTargetSource,也就是每次 SingletonTargetSource#getTarget() 都返回的是同一个对象。
TargetSource#isStatic()
在Spring AOP中,TargetSource可以分为“静态”和“动态”两类,这两者的区别在于代理对象的目标对象是在代理创建时就确定好(静态)还是在运行时动态确定(动态)。
1. 静态TargetSource:
- 目标对象确定性: 静态TargetSource在代理对象创建时,目标对象就已经确定了,它不会随着时间或者特定条件的改变而改变。通常,静态TargetSource的目标对象是单例(Singleton)的,即整个应用程序生命周期内只有一个实例。
- 作用: 静态TargetSource适用于那些在整个应用程序中共享同一个实例的目标对象,这种目标对象通常是无状态的、可共享的,例如服务类、工具类等。使用静态TargetSource可以带来性能上的优势,因为代理对象只需要在创建时确定一次目标对象即可。
2. 动态TargetSource:
- 目标对象的动态性: 动态TargetSource在代理对象创建后,可以在运行时动态地改变代理对象的目标对象。这种改变可以基于特定的条件、用户权限、请求内容等动态决定。动态TargetSource的目标对象可以随着时间、请求、或者其他因素的改变而改变。
- 作用: 动态TargetSource适用于那些需要根据特定条件或者动态情况来确定目标对象的场景。例如,在多数据源切换时,根据用户的请求或者业务逻辑需要选择不同的数据库连接。动态TargetSource允许在运行时动态选择代理的目标对象。
作用比较:
-
静态TargetSource适用于那些整个应用程序生命周期内只需要一个实例的目标对象,比如无状态的服务类。
-
动态TargetSource适用于那些需要根据条件动态选择目标对象的场景,比如根据用户权限、请求内容等动态选择不同的实例。
选择静态还是动态的TargetSource取决于你的应用需求。如果你的目标对象是无状态的、可共享的,使用静态TargetSource可以带来性能上的优势。如果你的目标对象是有状态的、需要根据条件动态切换的,使用动态TargetSource可以实现更灵活的代理目标对象选择逻辑。
在Spring AOP中,CglibAopProxy和JdkDynamicAopProxy是两种不同的AOP代理方式,分别使用CGLIB(Code Generation Library)和JDK动态代理技术来创建代理对象。这两者在处理isStatic()方法时有所不同。
3. CglibAopProxy:
在CglibAopProxy中,StaticUnadvisedExposedInterceptor 和 DynamicUnadvisedExposedInterceptor 是两个不同的拦截器类。它们分别用于处理静态代理和动态代理。
StaticUnadvisedExposedInterceptor:
StaticUnadvisedExposedInterceptor 主要用于处理基于接口的静态代理,它的实例被用于拦截那些实现了接口的目标对象。这个拦截器的构造函数接受一个目标对象作为参数,并且这个目标对象是在拦截器创建时就已经确定的,是静态的,不会在运行时改变。
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget())
在这里,this.advised.getTargetSource().getTarget() 是一个静态的目标对象,它在代理创建时就已经确定,不会在后续的运行时动态改变。
DynamicUnadvisedExposedInterceptor:
DynamicUnadvisedExposedInterceptor 用于处理CGLIB或者其他动态代理方式创建的代理对象。这个拦截器的构造函数接受一个TargetSource作为参数,TargetSource可以动态地确定目标对象。DynamicUnadvisedExposedInterceptor 的目标对象是动态的,它可能会在运行时根据条件或者其他因素改变。
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource())
在这里,this.advised.getTargetSource() 返回的是一个TargetSource对象,这个TargetSource可能会根据特定的条件在运行时切换目标对象。因此,DynamicUnadvisedExposedInterceptor 用于处理动态代理,目标对象可能在运行时发生改变。
4. JdkDynamicAopProxy:
Jdk的isStatic的处理和cglib有点区别,Jdk Proxy每次调用会通过TargetSource#getTarget()获取目标对象。最后通过如果isStatic为false得时候会去releaseTarget。
相关文章:

SpringAOP源码解析之TargetSource(四)
前言 在Spring框架中,TargetSource是一个接口,用于封装获取目标对象(也就是被代理的对象)的逻辑。它的主要作用是提供代理对象使用的目标对象,并且允许在运行时动态地切换目标对象。TargetSource在Spring的AOP&#x…...
Centos7 安装nvidia显卡驱动
参考一:https://blog.csdn.net/awen19921106/article/details/131331450 参考二:https://www.cnblogs.com/lishanyang/p/17326021.html 报错一: ERROR: Unable to find the kernel source tree for the currently running kernel. Please …...

22 行为型模式-状态模式
1 状态模式介绍 2 状态模式结构 3 状态模式实现 代码示例 //抽象状态接口 public interface State {//声明抽象方法,不同具体状态类可以有不同实现void handle(Context context); }...

Jetpack:018-Jetpack中的导航一
文章目录 1. 概念介绍2. 使用方法2.1 基本概念2.2 传统用法2.3 新的用法 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack库中对话框相关的内容,本章回中主要介绍 导航。闲话休提,让我们一起Talk Android Jetpack吧! 1. 概念介绍 我…...

Linux常见问题解决操作(yum被占用、lsb无此命令、Linux开机进入命令界面等)
Linux常见问题解决操作(yum被占用、lsb无此命令、Linux开机进入命令界面等) 问题一、新安装的Linux使用命令lsb_release提示无此命令,需先安装再使用 Linux安装lsb命令 lsb是Linux Standard Base的缩写(Linux基本标准ÿ…...

层次式架构的设计理论与实践
层次式架构的设计理论与实践 层次式架构概述 层次式架构的定义和特性 定义 特性 层次式架构的一般组成(表现层、中间层、数据访问层和数据层) 表现层框架设计 设计模式 MVC MVP MVVM XML技术 UIP设计思想 表现层动态生成设计思想(基于XML界面管理技术) 中间层架构设计 业务…...
【shell】read -t -n1
if read -t 5 -p "Please enter your name:" name thenecho "Hello, $name, welcome to my script" else#起到换行的作用echo#输入计数 -n1read -n1 -p "Do you want to continue [Y/N]?" answercase $answer inY | y) echoecho "Fine, co…...

【嵌入式项目应用】__cJSON在单片机的使用
目录 前言 一、JSON和cJson 二、cJSON是如何表示JSON数据的 三、如何封装完整的JSON数据 1. 先将串口打通,方便电脑查看log日志。 2. 增加cjson.c文件,已经在main.c中 3. 准备打包如下的JSON包 4. 代码部分,先将几个部分初始化指针 …...

【智能家居】
面向Apple developer学习:AirPlay | Apple Developer Documentation Airplay AirPlay允许人们将媒体内容从iOS、ipad、macOS和tvOS设备无线传输到支持AirPlay的Apple TV、HomePod以及电视和扬声器上。 网页链接的最佳实践 首选系统提供的媒体播放器。内置的媒体播…...

Android stdio 无法新建或打开AIDL文件(解决方法)
1.在gradle文件中添加如下代码 2.AIDL要求minsdk>16,并且要使aidl true(在Gradle中添加) android{ buildFeatures { aidl true } } 我们看见,可以创建AIDL文件了 3.接着,我们看到文件出现如下提示 4.在gradle…...

如何进行渗透测试以提高软件安全性?
对于各种规模的企业和组织来说,软件安全是一个至关重要的问题。随着网络攻击越来越复杂,软件中的漏洞越来越多,确保你的软件安全比以往任何时候都更重要。提高软件安全性的一个有效方法是渗透测试(penetration testing)…...

YOLOv5 添加 OTA,并使用 coco、CrowdHuman数据集进行训练。
YOLO-OTA 第一步:拉取 YOLOv5 的代码第二步:添加 ComputeLossOTA 函数第二步:修改 train 和 val 中损失函数为 ComputeLossOTA 函数1、在 train.py 中 首先添加 ComputeLossOTA 库。2、在 train.py 修改初始化的损失函数3、在 train.py 修改一…...

SpringBoot 日志
目录 1.如何使用日志 2.自定义打印日志 3.日志级别 3.1 日志从低到高级别 3.2 日志级别设置 为什么 Spring Boot 可以打印日志?并设置日志级别? 4.日志的持久化 5.lombok——更加简单的输出日志 5.1 使用slf4j 注解输出日志 5.2 lombok 执行原…...

非小米笔记本小米妙享中心安装最新教程 3.2.0.464 兼容所有Windows系统
小米妙享中心 3.2.0.464 版本帮助 : 支持音频流转、屏幕镜像、屏幕拓展、键鼠拓展、无线耳机、小米互传 目录 小米妙享中心 3.2.0.464 版本帮助 : 1.常规教程使用安装包方式安装失败 或者 1.1安装失败可使用大佬的加载补丁方法解决 补充卸载残留 1.2 截图存档 2. 本教程…...

基于大数据的社交平台数据爬虫舆情分析可视化系统 计算机竞赛
文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于大数据…...
MYSQL(事务)
一、什么是事务,四大特性 事务:一组操作的集合,它是一个不可分割的单位,事务会将这些操作作为一个整体一起像系统提交,这些操作要么同时成功,要么同时失败 四大特性(ACID) 原子性&am…...
npm start启动的是什么
npm start 命令是在一个 Node.js 项目中执行的一个自定义命令,用于启动该项目。该命令是在 package.json 文件中定义的,通常被用于启动一个 Web 应用程序或服务。 具体来说,当在项目目录下执行 npm start 命令时,npm 将会在该项目…...

基于PyTorch的MNIST手写体分类实战
第2章对MNIST数据做了介绍,描述了其构成方式及其数据的特征和标签的含义等。了解这些有助于编写合适的程序来对MNIST数据集进行分析和识别。本节将使用同样的数据集完成对其进行分类的任务。 3.1.1 数据图像的获取与标签的说明 MNIST数据集的详细介绍在第2章中已…...
conda 复制系统环境
直接复制 想要通过 conda 直接复制一个已存在的环境,你可以使用 conda create 命令并配合 --clone 参数。以下是具体步骤: 查看现有的环境: 首先,你可以使用以下命令来查看所有的 conda 环境: conda env list这会给你一个环境列表…...

如何在Microsoft Visual Studio 中使用Cpp代码调用python代码
Microsoft Visual Studio中Cpp调用Python代码 本文介绍如何在Microsoft Visual Studio中,开发cpp项目时,调用python代码。 文章目录 Microsoft Visual Studio中Cpp调用Python代码前言一、Cpp生成exe文件1.1 安装python环境1.2 配置Microsoft Visual Stu…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...