#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析
Posted 老王学源码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析相关的知识,希望对你有一定的参考价值。
@[TOC](Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析)
前言
实现 Spring AOP 大体会分如下几步:
- 找到 Pointcut 所匹配的所有 join point 对应的类
- 为 Pointcut 匹配到的类生成动态代理
- 通过动态代理类执行 Pointcut 对应的 Advice
- 将 Spring AOP 与 Spring IoC 进行结合
之前我们已经分析了前面三步,下面我们来看下 Spring AOP 是怎么与 Spring IoC 进行结合的。
版本约定
Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)
正文
Spring AOP 是一个相对独立的框架,它是通过 org.springframework.aop.framework.ProxyFactory
来对外提供代理功能的。
ProxyFactory
ProxyFactory 是生成 Spring AOP 代理类的总入口,每次在创建 proxy bean 时,都会 new 一个 ProxyFactory 来进行处理。
ProxyFactory 共提供了 5 个方法,2 个实例方法,3 个静态方法。其中,Spring AOP 创建代理的标准方法是实例方法 public Object getProxy(ClassLoader classLoader)
下面,我们来看下这个方法在 Spring 源码中是如何使用的?
bean 创建时,创建 AOP 代理类
bean 在正常创建过程中,会分为三步:
- AbstractAutowireCapableBeanFactory#createBeanInstance()
创建 bean 的实例 - AbstractAutowireCapableBeanFactory#populateBean()
填充 bean 的依赖 - AbstractAutowireCapableBeanFactory#initializeBean()
初始化 bean
其中,在 初始化 bean
时,会通过 AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization()
来产生 AOP 代理类。
产生 Spring AOP 代理是通过调用 AbstractAutoProxyCreator#createProxy()
:
// AbstractAutoProxyCreator#wrapIfNecessary()
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName))
return bean;
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey)))
return bean;
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName))
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
// Create proxy if we have advice.
// 创建 Spring AOP 代理类
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY)
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
bean 初始化时,根据匹配的 Advice 创建 Spring AOP 代理类,是 Spring 框架中调用 ProxyFactory#getProxy() 最频繁的地方。
从源码可以看出,ProxyFactory 使用的简化流程如下:
// new 一个 ProxyFactory 实例
ProxyFactory proxyFactory = new ProxyFactory();
// 拷贝代理配置
proxyFactory.copyFrom(this);
// 添加 Advisors
proxyFactory.addAdvisors(advisors);
// 设置 TargetSource
proxyFactory.setTargetSource(targetSource);
// 生成代理类
return proxyFactory.getProxy(classLoader);
@Resource 注入 @Lazy bean
通过 @Resource 注入依赖 bean 时,如果将 bean 标记为 @Lazy 的话,Spring 在 populateBean 填充依赖
时,会为依赖 bean 生成一个代理类进行注入,从而实现懒加载的功能。
相应的源码处理流程如下:
@Autowired 注入 @Lazy bean
通过 @Autowired 注入依赖 bean 时,如果将 bean 标记为 @Lazy 的话,Spring 在 populateBean 填充依赖
时,会为依赖 bean 生成一个代理类进行注入,从而实现懒加载的功能。
相应的源码处理流程如下:
TargetSource: org.springframework.aop.TargetSource
从上面的源码例子中,可以看出 TargetSource
是 Spring AOP 生成代理类时一个很重要的属性。
TargetSource
代表着代理类在执行时,最终路由到的目标类。
通过 TargetSource#getTarget()
来获取目标类,通过实现这个方法能实现不同的功能。
比如:
- 在 bean 创建阶段,Spring 使用的是
SingletonTargetSource
,这样,对于 scope=singleton 的 bean,每次调用代理类,都会路由到同一个目标类。 - 在 @Resource、@Autowired 注入 @Lazy 标记的 bean 时,就自定义的实现了 TargetSource#getTarget() 方法。
也就是说,@Lazy 标记的 bean 在依赖注入时,注入的是一个代理 bean,它没有真正走依赖 bean 的初始化流程,而是在第一次使用到 bean 的方法时,才会通过 TargetSource#getTarget()` 方法获取真正的目标类去执行相应的方法。
Spring AOP 代理类 vs 代理类
Spring AOP 代理类
与 代理类
这两个概念是有区别的。
-
代理类
:
这个概念比较宽泛,通过ProxyFactory#getProxy()
方法可以产生一个代理类。但是产生的代理类不一定是 Spring AOP 代理类。
比如上面提到的 @Lazy 标记的 bean,在依赖注入时,虽然也是通过 ProxyFactory#getProxy() 来产生代理类的,但是,它没有添加 Advisor,没有被 Advice 增强,不能算是 Spring AOP 代理类。 Spring AOP 代理类
:
它专指被 Spring AOP Advice 增强的代理类,它的限定条件是:ProxyFactory 在产生代理类时,要添加 Advisor。
小结
Spring AOP 代理类的产生是在 bean 创建的第三阶段 initializeBean
时: AbstractAutoProxyCreator#wrapIfNecessary()
。
产生代理的总入口是 ProxyFactory#getProxy()
。
@Resource、@Autowired 在注入 @Lazy 标记的 bean 时,也会通过 ProxyFactory#getProxy()
来产生代理类,以实现懒加载的功能。
但是,这里产生的代理类,并不是 Spring AOP 代理类,并没有被 Spring AOP Advice 进行增强。
如果本文对你有所帮助,欢迎点赞收藏!
有关 Spring 源码方面的问题欢迎一起交流,备注:51cto (vx: Kevin-Wang001)
博主好课推荐:
课程 | 地址 |
---|---|
Dubbo源码解读——通向高手之路 | https://edu.51cto.com/course/23382.html |
正则表达式基础与提升 | https://edu.51cto.com/course/16391.html |
以上是关于#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析
#yyds干货盘点# 老王读Spring AOP-1Pointcut如何匹配到 join point