#yyds干货盘点#Spring源码三千问Spring AOP 中 TargetSource 的作用及原理分析

Posted 老王学源码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点#Spring源码三千问Spring AOP 中 TargetSource 的作用及原理分析相关的知识,希望对你有一定的参考价值。

@[TOC](Spring AOP 中 TargetSource 的作用及原理分析)

前言

TargetSourceProxyFactory 创建代理类时一个很重要的概念。
搞清楚 TargetSource 是什么,对我们理解 Spring AOP 有很大的帮助!

版本约定

Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

TargetSource 的作用是用来获取 AOP 调用的当前“目标”(target)。
在调用 AOP 代理对象的方法时,在执行完所有的 advice chain 之后,最终会通过反射调用这个目标 target 的方法。

如果 TargetSource 是“静态”的,它将始终返回相同的目标 target,那么 Spring AOP 框架就可以对这种目标 Target 进行缓存,这样就不必每次都通过 TargetSource#getTarget() 来获取目标对象。
如果 TargetSource 是"动态"的,它也可以支持对象池(CommonsPool2TargetSource)、热交换(HotSwappableTargetSource)等功能。

应用程序开发人员通常不需要直接使用 TargetSource,这是一个 AOP 框架接口。

普通的 AOP 代理创建使用的 TargetSource

Spring 中 99% 的 AOP 代理 bean 都会走 AutoProxyCreator#wrapIfNecessary() 来进行创建。
它使用的 TargetSource 是 SingletonTargetSource,也就是每次 SingletonTargetSource#getTarget() 都返回的是同一个对象。

@Async、@Valid 产生的代理使用的 TargetSource

@Async、@Valid 标记的 bean 是使用 AbstractAdvisingBeanPostProcessor 来产生代理的。
查看源码,可以发现这种情况最终也是使用的 SingletonTargetSource

@Lazy 产生的代理使用的 TargetSource

@Lazy 使用在 @Resource/@Autowired 注入的属性上时,在依赖注入时,会注入一个代理对象,等真正调用代理 bean 的方法时,才会通过 TargetSource#getTarget() 来获取到真实的 bean 对象。

@Resource 属性上使用 @Lazy 时

可以看到,通过 ProxyFactory 创建代理时,使用的是 TargetSource 的匿名内部类。
每次调用 TargetSource#getTarget() 时,没有使用缓存,都会重新走一遍依赖注入的流程。

@Autowired 属性上使用 @Lazy 时

可以看到,通过 ProxyFactory 创建代理时,使用的是 TargetSource 的匿名内部类。
每次调用 TargetSource#getTarget() 时,没有使用缓存,都会重新走一遍依赖注入的流程。

TargetSource#isStatic()

TargetSource 分为 “静态” 和 "动态" 两类:

  • Static TargetSource
    它将始终返回相同的目标 target, Spring 会对这种 静态的TargetSource 进行优化,不必每次调用目标对象的方法都通过 TargetSource#getTarget() 来获取目标对象。

  • Dynamic TargetSource
    对于 动态的TargetSource,每次调用目标对象的方法都需要通过 TargetSource#getTarget() 来获取目标对象。
    动态的TargetSource 在使用完之后,会调用 TargetSource#releaseTarget() 来释放目标对象。
    动态的TargetSource 可以支持对象池(CommonsPool2TargetSource)、热交换(HotSwappableTargetSource)等功能。

cglib 对 TargetSource#isStatic() 的处理

jdk proxy 对 TargetSource#isStatic() 的处理

小结

TargetSource 是用来获取 AOP 调用的当前“目标对象”(target)的。
TargetSource 分为 “静态” 和 "动态" 两类。
Spring 中绝大部分的场景都是使用的 SingletonTargetSource,SingletonTargetSource 是静态TargetSource。

@Lazy 使用的 TargetSource 是一个匿名内部类,它是 动态TargetSource,每次调用目标方法时都会调用 TargetSource#getTarget() 重新执行一遍依赖注入的流程,所以,会有一定的性能影响,不建议使用。可以考虑使用 ObjectProvider 进行代替,使用构造注入。


如果本文对你有所帮助,欢迎点赞收藏
有关 Spring 源码方面的问题欢迎留言一起交流...

公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…

阅读更多文章,请关注公众号: 老王学源码


博主好课推荐:

课程 地址
Dubbo源码解读——通向高手之路 https://edu.51cto.com/sd/2e565
正则表达式基础与提升 https://edu.51cto.com/sd/59587

以上是关于#yyds干货盘点#Spring源码三千问Spring AOP 中 TargetSource 的作用及原理分析的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#Spring源码三千问@Lazy延迟加载与延迟注入有什么区别?

#yyds干货盘点# Spring源码三千问Bean的Scope有哪些?scope=request是什么原理?

#yyds干货盘点# Spring源码三千问BeanDefinition详解——什么是 RootBeanDefinition?merged bean definition 又是什么鬼?

#yyds干货盘点# Spring源码三千问Spring动态代理:什么时候使用的 cglib,什么时候使用的是 jdk proxy?

#yyds干货盘点# Spring 源码三千问同样是AOP代理bean,为什么@Async标记的bean循环依赖时会报错?

#yyds干货盘点# Spring源码三千问为什么要用三级缓存来解决循环依赖问题?二级缓存行不行?一级缓存行不行?