Spring AOP核心源码解析

Spring AOP

在上一章节,笔者对Spring-Mybatis的核心思想做了详细介绍,目的是让读者能够更加清晰的认知Spring的全局生命周期,以及Spring是如何设计对外扩展的开放,本章将对Spring AOP的原理及源码进行详细说明。

Spring AOP应用

首先还是对Spring AOP的基本功能简单介绍。切面配置类

 

image

被增强的类

image

配置类

image

新建一个测试类

image

image

输出结果:

image

通过执行结果我们可以看到我们不需要修改任何原有的代码就可以改变代码的逻辑,其实在上一篇文章中笔者就已经对动态代理有所介绍,比如在Mybatis中的Mapper接口就是通过JDK动态代理,只不过我们的Mybatis代理需求相对复杂,而Spring AOP相对单一,因为Spring AOP是对自己内部的对象代理,也就是说Spring AOP是先装入Spring容器,在由其他的其他组件进行代理,而Mybatis和其恰好消防,Mybatis是先代理在装入Spring,所以我们在上一篇文章中在将代理对象整合到Spring中遇到了很多问题,如果读者对此没有印象建议回顾《Spring深度源码解析(七) Spring-Mybatis核心思想》。

Spring AOP源码解析

在对Spring应用做了简单介绍后,我们先思考一下如果我们自己实现一个SpringAOP,如何去实现呢,如何动态的去改变类的创建方式呢?在《Spring源码深度分析(六)》笔者提到,在对Spring实例化前后、初始化前后,Spring都做了循环后置处理器的处理提供对外扩展,再思考如果我们是对类进行代理,那么会采用CGLIB的方式进行代理,为什么SpringAOP实现了切面代理,我们关注这个注解

image

进入这个注解

image

可以看到这里又有这个@Import注解,@Import什么用我就不介绍了,笔者在Spring-Mybatis做了大量文章。

image

这里我们又看到了ImportBeanDefinitionRegistrar,这里我在啰嗦几句Spring提供了很多种对外的拓展方式,ImportBeanDefinitionRegistrar就是其中一种,如果自己定的类实现了它就可以获取工厂注册器。


@Override
  public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

    AnnotationAttributes enableAspectJAutoProxy =
        AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    if (enableAspectJAutoProxy != null) {
      if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }
      if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
        AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
      }
    }

注意这段代码:

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
->registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
->registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
->registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);

其实就是向我们的工厂注册了这个一个类AnnotationAwareAspectJAutoProxyCreator,我们点开这么类

image

可以看到这个类实现了BeanPostProcessor,说明这个类同样是后置处理器,既然这是后置处理器,就可以改变我们工厂内部的对象,既然能够改变我们的对象是不是就能将我们的某些对象进行代理?答案是肯定的,那么这就解惑了我在上文提出的Spring通过什么手段完成的代理,读者是不是觉得Spring的后置处理器很神奇啊,到哪都有它,好了我们对AnnotationAwareAspectJAutoProxyCreator做了简要分析,接下来将对Spring AOP做详细介绍。Spring AOP源码

首先我们将代码停留在doCreateBean(),断点采用的是被AOP增强的person类

image

然后这里的instanceWrapper为空,我们下一步,

image

看到我们的person对象已经创建成功,注意我们发现这里的person对象并没有被代理,而仅仅是被创建出来,为什么Spring没有在创建对象的时候进行拦截代理呢?道理很简单,我们在IOC的文章提出了Spring在创建对象后还需要执行属性注入,生命周期等步骤,如果我们提前将对象进行代理,我们能否对对象实施属性注入、生命周期这都不能确定。那么Spring是在哪里进行代理的呢?我们将代码停在属性注入的下面

image

发现并没有被代理,我们执行下一步

image

发现该对象已经被我们的CGLIB进行代理,那么在这段代码里面就进做了什么操作呢?我们跟踪下一这段代码:exposedObject = initializeBean(beanName, exposedObject, mbd);我们一路跟踪停在这里

image

然后点击去

image

循环我们的后置处理器获取我们所需要的AspectJAwareAdvisorAutoProxyCreator->postProcessAfterInitialization

image

然后我们再度将代码停在这里

image

看名字我们大概能猜到这里就是代理的关键代码,我们跟进下去

image

然后获取一些adviors

image

我们其实可以猜到,这里就是获取我们的AspectTest的信息

image

好了,既然我们获取了我们的代理配置,那么就要开始对我们所符合标准的代理对象进行代理了

image

进createProxy方法在-》 proxyFactory.getProxy(getProxyClassLoader());

image

很明显这里就是真正创建代理的角色了,继续跟踪代码

image

这里就是根据什么样的需求创建什么样的代理方式,注意这里仅仅只是方式,并不是真正创建代理对象的逻辑,比如我们这里代理的是类,那么会选择CGLIB的方式

image

然后我们再回到前面的代码

image

可以看到createAopProxy()获取的就是我们创建代理的方式,至于我们的getProxy(),笔者就不多写了,内部就是如何使用cglib增强的代码,笔者在@Configuration中对如何通过cglib代理对象做了大量分析,这里就略过,那么我们已经知道了Spring AOP的代理流程,那么其实还缺少一样东西,不知读者是否发现我们的adviors并不知道什么时候就存在了呢?接下来我们就去解答这个问题,首先我们将代码停在doCreateBean():的上面,doCreateBean()我们在IOC创建Bean进行了详细介绍,就是开始创建Bean,那么对adviors的操作明显就是在创建Bean之前就完成了,为了验证我们将代码跟进:

image

进入代码

image

注意这个getBeanPostProcessors(),一共有九个,这里会循环获取

image

找到我们AOP注册的后置处理器,然后点进去

image

注意postProcessBeforeInstantiation,其实就是实例化之前的操作,Spring的命名十分规范,我们在上文介绍了这是在doCreateBean之前操作的,所以称为实例化之前,我们停留在这里

image

点击去shouldSkip,继续跟踪跟踪

image

然后进入

image

然后进入会发现这个buildAspectJAdvisors方法很长,我们直接找到关键代码

image

可以看到我们就是用过this.advisorFactory.getAdvisors(factory);这句代码获取我们切面的方法,我们在进入getAdvisors(factory)


@Override
  public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
    final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
    final String aspectName = maaif.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
        new LazySingletonAspectInstanceFactoryDecorator(maaif);

    final List<Advisor> advisors = new LinkedList<Advisor>();
    for (Method method : getAdvisorMethods(aspectClass)) {
      Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
      if (advisor != null) {
        advisors.add(advisor);
      }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
      advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    for (Field field : aspectClass.getDeclaredFields()) {
      Advisor advisor = getDeclareParentsAdvisor(field);
      if (advisor != null) {
        advisors.add(advisor);
      }
    }

    return advisors;
  }

其实这里面就是通过反射的方式获取我们的方法,返回后在存起来交给我们后面对被代理类进行增强,至此Spring AOP源码分析到此为止,Spring 事物其实和我所提到Spring源码第七章和本章思想大致一致,笔者就不在对事物进行单独叙述了,下一章将会更新SpringMVC。

文章来源微信公众号《七天0》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值