当前位置: 首页 > news >正文

SpringAOP源码解析之TargetSource(四)

前言

在Spring框架中,TargetSource是一个接口,用于封装获取目标对象(也就是被代理的对象)的逻辑。它的主要作用是提供代理对象使用的目标对象,并且允许在运行时动态地切换目标对象。TargetSource在Spring的AOP(面向切面编程)中非常重要,它定义了代理对象的目标是谁以及在何时获取目标对象。

具体来说,TargetSource接口定义了以下两个方法:

  1. getTarget():这个方法用于获取目标对象。AOP代理对象在执行方法时,会先调用getTarget()方法获取目标对象,然后再在目标对象上执行相应的方法。

  2. releaseTarget(Object target):这个方法用于释放目标对象。在一些特殊的场景中,可能需要手动释放目标对象,以便它可以被垃圾回收或者被缓存起来以供下次使用。

  3. isStatic() 方法:该方法用于指示目标对象是否是静态的。如果目标对象是静态的,那么TargetSource可以在代理创建时确定代理对象的类型,从而进行更好的性能优化。如果目标对象是动态的(例如在运行时根据条件切换不同的实例),则返回false。

  4. 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 来管理目标对象的池化。
  • 特点: 可以灵活地控制对象池的大小和行为,适用于需要对象池管理的场景。

区别和使用场景总结:

  • PrototypeTargetSourceSingletonTargetSource 分别适用于需要每次请求都创建新实例和整个应用程序生命周期内共享同一个实例的场景。

  • 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基本标准&#xff…...

层次式架构的设计理论与实践

层次式架构的设计理论与实践 层次式架构概述 层次式架构的定义和特性 定义 特性 层次式架构的一般组成(表现层、中间层、数据访问层和数据层) 表现层框架设计 设计模式 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&#xff09…...

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…...

DAY35 435. 无重叠区间 + 763.划分字母区间 + 56. 合并区间

435. 无重叠区间 题目要求:给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 示例 1: 输入: [ […...

代码随想录算法训练营第2天| 977有序数组的平方、209长度最小的子数组。

JAVA代码编写 977. 有序数组的平方 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。 示例 1: 输入:nums [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释&…...

微信小程序通过startLocationUpdate,onLocationChange获取当前地理位置信息,配合腾讯地图解析获取到地址

先创建个getLocation.js文件 //获取用户当前所在的位置 const getLocation () > {return new Promise((resolve, reject) > {let _locationChangeFn (res) > {resolve(res) // 回传地里位置信息wx.offLocationChange(_locationChangeFn) // 关闭实时定位wx.stopLoc…...

C/C++字符三角形 2020年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C字符三角形 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C字符三角形 2020年12月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 给定一个字符,用它构造一个底边长5个字…...

Python数据挖掘:入门、进阶与实用案例分析——基于非侵入式负荷检测与分解的电力数据挖掘

文章目录 摘要01 案例背景02 分析目标03 分析过程04 数据准备05 属性构造06 模型训练07 性能度量08 推荐阅读赠书活动 摘要 本案例将根据已收集到的电力数据,深度挖掘各电力设备的电流、电压和功率等情况,分析各电力设备的实际用电量,进而为电…...

基于 Qt控制开发板 LED和C语言控制LED渐变亮度效果

## 资源简介 在STM32开发板,板载资源上有两个可自由控制的 LED。如下图原理 图其中我们以操作 LED1 为示例,LED1 为出厂系统的心跳指示灯。 ## 应用实例 想要控制这个 LED,首先出厂内核已经默认将这个 LED 注册成了 gpio-leds类型设备。所以我们可以直接在应用层接口直接…...

Android 11.0 禁用插入耳机时弹出的保护听力对话框

1.前言 在11.0的系统开发中,在某些产品中会对耳机音量调节过高限制,在调高到最大音量的70%的时候,会弹出音量过高弹出警告,所以产品 开发的需要要求去掉这个音量弹窗警告功能 2.禁用插入耳机时弹出的保护听力对话框的核心类 frameworks\base\packages\SystemUI\src\com\and…...

微信小程序案例2-3:婚礼邀请函

文章目录 一、运行效果二、知识储备(一)导航栏配置(二)标签栏配置(三)vw、vh单位(四)video组件(五)表单组件(六)Node.js概述 三、实现…...

K8S部署Dashboard

获取recommended.yaml文件 Dashboard是官方提供的一个UI,可用于基本管理K8s资源。 YAML下载地址: wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml如果网络错误无法直接下载,可以直接访问…...

【OJ比赛日历】快周末了,不来一场比赛吗? #10.29-11.04 #7场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…)比赛。本账号会推送最新的比赛消息,欢迎关注! 以下信息仅供参考,以比赛官网为准 目录 2023-10-29(周日) #3场比赛2023-10-30…...