【老王读Spring AOP-4】Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析

前言

实现 Spring AOP 大体会分如下几步:

  1. 找到 Pointcut 所匹配的所有 join point 对应的类
  2. 为 Pointcut 匹配到的类生成动态代理
  3. 通过动态代理类执行 Pointcut 对应的 Advice
  4. 将 Spring AOP 与 Spring IoC 进行结合

之前我们已经分析了前面三步,下面我们来看下 Spring AOP 是怎么与 Spring IoC 进行结合的。

版本约定

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

正文

Spring AOP 是一个相对独立的框架,它是通过 org.springframework.aop.framework.ProxyFactory 来对外提供代理功能的。

ProxyFactory

ProxyFactory2

ProxyFactory 是生成 Spring AOP 代理类的总入口,每次在创建 proxy bean 时,都会 new 一个 ProxyFactory 来进行处理。

ProxyFactory 共提供了 5 个方法,2 个实例方法,3 个静态方法。其中,Spring AOP 创建代理的标准方法是实例方法 public Object getProxy(ClassLoader classLoader)

proxyFactory

下面,我们来看下这个方法在 Spring 源码中是如何使用的?

bean 创建时,创建 AOP 代理类

bean 在正常创建过程中,会分为三步:

  1. AbstractAutowireCapableBeanFactory#createBeanInstance()
    创建 bean 的实例
  2. AbstractAutowireCapableBeanFactory#populateBean()
    填充 bean 的依赖
  3. AbstractAutowireCapableBeanFactory#initializeBean()
    初始化 bean

其中,在 初始化 bean 时,会通过 AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization() 来产生 AOP 代理类。

生成代理类的具体过程分析请戳:如何为 Pointcut 匹配的类生成动态代理类?

产生 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;
}

beanCreateAOP

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 生成一个代理类进行注入,从而实现懒加载的功能。

相应的源码处理流程如下:
resourceInjectLazy

@Autowired 注入 @Lazy bean

通过 @Autowired 注入依赖 bean 时,如果将 bean 标记为 @Lazy 的话,Spring 在 populateBean 填充依赖 时,会为依赖 bean 生成一个代理类进行注入,从而实现懒加载的功能。

相应的源码处理流程如下:
autowiredInjectLazy

TargetSource: org.springframework.aop.TargetSource

从上面的源码例子中,可以看出 TargetSource 是 Spring AOP 生成代理类时一个很重要的属性。

TargetSource 代表着代理类在执行时,最终路由到的目标类。
通过 TargetSource#getTarget() 来获取目标类,通过实现这个方法能实现不同的功能。
比如:

  1. 在 bean 创建阶段,Spring 使用的是 SingletonTargetSource,这样,对于 scope=singleton 的 bean,每次调用代理类,都会路由到同一个目标类。
  2. 在 @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 IoC源码分析&测试代码下载
老王读Spring AOP源码分析&测试代码下载

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

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


系列博文:
【老王读Spring AOP-0】SpringAop引入&&AOP概念、术语介绍
【老王读Spring AOP-1】Pointcut如何匹配到 join point
【老王读Spring AOP-2】如何为 Pointcut 匹配的类生成动态代理类
【老王读Spring AOP-3】Spring AOP 执行 Pointcut 对应的 Advice 的过程
【老王读Spring AOP-4】Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析
【老王读Spring AOP-5】@Transactional产生AOP代理的原理
【老王读Spring AOP-6】@Async产生AOP代理的原理
【Spring 源码阅读】Spring IoC、AOP 原理小总结

相关阅读:
【Spring源码三千问】Spring动态代理:什么时候使用的 cglib,什么时候使用的是 jdk proxy?
【Spring源码三千问】Advice、Advisor、Advised都是什么接口?
【Spring源码三千问】没有AspectJ,Spring中如何使用SpringAOP、@Transactional?
【Spring源码三千问】Spring AOP 中 AbstractAdvisorAutoProxyCreator、AbstractAdvisingBeanPostProcessor的区别
【Spring 源码三千问】同样是AOP代理bean,为什么@Async标记的bean循环依赖时会报错?

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王学源码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值