Ref: https://juejin.cn/post/6844903856778772494

1、概述

Aop 是面向接口的,也即是面向方法的,实现是在 IOC 的基础上,Aop 可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离,比如 Spring 的事务,通过事务的注解配置,Spring 会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略,aop 的实现主要包括了两个部分:

  • 匹配符合条件的方法 (Pointcut)
  • 对匹配的方法增强 (JDK 代理、cglib 代理)

spring 针对 xml 配置和配置自动代理的 Advisor 有很大的处理差别:

  • 在 IOC 中主要是基于 XML 配置分析的,
  • 在 AOP 的源码解读中,则主要从自动代理的方式解析

分析完注解的方式,再分析基于 xml 的方式。

2、案例准备

下面是 spring aop 的用法 也是用于源码分析的案例
切面类:TracesRecordAdvisor

  1. @Aspect
  2. @Component
  3. public class TracesRecordAdvisor {
  4. @Pointcut("execution(* spring.action.expend.aop.services.*.*(..))")
  5. public void expression() {
  6. }
  7. @Before("expression()")
  8. public void beforePrint()
  9. {
  10. System.out.println("进入服务,记录日志开始....");
  11. }
  12. @AfterReturning("expression()")
  13. public void afterPrint()
  14. {
  15. System.out.println("退出服务,记录日志退出.....");
  16. }
  17. }

xml 配置: aop 的注解启用只需要在 xml 中配置这段代码即可,这个是作为入口
<aop:aspectj-autoproxy/>
服务类:PayServiceImpl 使用 jdk 代理 所以要有一个接口

@Service
public class PayServiceImpl implements PayService {
    public void payMoneyService() {
        System.out.println("付款服务正在进行...");
    }
}

测试方法:

@Test
public void springAopTestService() {
    ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-aop.xml");
    PayService payService= (PayService) applicationContext.getBean("payServiceImpl");
    payService.payMoneyService();
}

执行结果:

进入服务,记录日志开始....
付款服务正在进行...
退出服务,记录日志退出.....

从上面的执行结果看,payMoneyService 方法的确是被增强了。

3、BeanFactoryPostProcessor

在读 spring 源码时,我想首先来看下 BeanFactoryPostProcessorBeanPostProcess, 这两个接口都是在 spring 通过配置文件或者 xml 获取 bean 声明生成完 BeanDefinition 后允许我们对生成 BeanDefinition 进行再次包装的入口。
首先看下 BeanFactoryPostProcessor 的定义:

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}

方法 postProcessBeanFactory 的参数为 ConfigurableListableBeanFactory,前文说过 beanFactory 用来获取 bean 的,而 ConfigurableListableBeanFactory 继承接口 SingletonBeanRegistry 和 BeanFactroy,所以可以访问到已经生成过的 BeanDefinitions 集合,如果某个类实现该接口,spring 会注册这个类,然后执行这个类的 postProcessBeanFactory 方法,以便我们对 BeanDefinition 进行扩展。

对于 BeanFactoryPostProcessor 只做简单的介绍,只是说明在 Spring 中,我们可以修改生成后的 BeanDefinition,这里住下看下 Spring 是如何注册 BeanFactoryPostProcessor 并执行 postProcessBeanFactory 的。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            prepareRefresh();
             //核心方法1
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            prepareBeanFactory(beanFactory);
            try {
                postProcessBeanFactory(beanFactory);
                 //核心方法2 执行BeanFactoryPostProcessor
                invokeBeanFactoryPostProcessors(beanFactory);
                //核心方法 3 注册BeanPostProcessor
                registerBeanPostProcessors(beanFactory);
                // Initialize message source for this context.
                initMessageSource();
                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();
                // Initialize other special beans in specific context subclasses.
                onRefresh();
                // Check for listener beans and register them.
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
                // Last step: publish corresponding event.
                finishRefresh();
            }
            catch (BeansException ex) {
                 ............
                throw ex;
            }
            finally {
                 ............
                resetCommonCaches();
            }
        }
    }

核心方法 1:obtainFreshBeanFactory 就是前两篇所说的生成 BeanDefinition 的入口,invokeBeanFactoryPostProcessors 核心方法 2 就是执行 BeanFactoryPostProcessor 接口的方法。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}

通过方法 getBeanFactoryPostProcessors 获取注册 BeanFactoryPostProcessor,然后来看看如何添加一个处理器:

@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
    this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
}

对于方法 invokeBeanFactoryPostProcessors 不再往下看了,里面的方法大致先对 BeanFactoryPostProcessor 进行排序,排序的标准是是否实现了 PriorityOrdered,然后根据设置的 order 大小指定执行顺序,生成一个排序集合和一个普通的集合,最后执行 invokeBeanFactoryPostProcessors。

private static void invokeBeanFactoryPostProcessors(
    Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

    for (BeanFactoryPostProcessor postProcessor : postProcessors) {
        //执行到自定义的BeanFactoryPostProcessor
        postProcessor.postProcessBeanFactory(beanFactory);
    }
}

这个方法就会循环先前注册的 BeanFactoryPostProcessor 集合,然后执行 postProcessBeanFactory。

4、BeanPostProcessor

与 BeanFactoryPostProcessor 相比,BeanPostProcess 就重要得多了,因为 Spring 的注解、AOP 等都是通过这个接口的方法拦截执行的,它贯穿了 Bean 创建过程的整个生命周期,在 IOC 阶段,Spring 只注册 BeanPostProcessor,执行则放到了 Bean 的实例化创建阶段。

首先看下 BeanPostProcessor 的接口定义:

public interface BeanPostProcessor {
    //在bean创建 属性赋值之后  Aware接口执行之后执行
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //在init-method afterPropertiesSet 执行之后执行
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

在 bean 的声明周期中,下面的序列是 bean 创建后要执行的接口和方法顺序:

  • 实例化(autowire Constructor 或者 InstantiationAwareBeanPostProcessor)
  • 属性赋值 (populateBean)
  • Aware 接口(如果 bean 实现了的话)
  • BeanPostProcessor.postProcessBeforeInitialization
  • PostConstruct、InitializingBean.afterPropertiesSet
  • BeanPostProcess.postProcessAfterInitialization

其中通过注解引入依赖的方式就是在 AutowiredAnnotationBeanPostProcessor 这个类中实现的,而接下来要分析的 Spring Aop 也是从这里开始的,这个类叫 AnnotationAwareAspectJAutoProxyCreator.

5、NameSpaceHanlder

在 Spring 中,任何的技术都是在 IOC 的基础上进行的,Aop 也不例外,程序会首先读取 xml 配置文件,然后对读取到的标签先查找命名空间,然后找对应的 NameSpaceHandler,最终调用 parse 方法解析标签。

aop 标签的解析,使用纯注解的方式 aop:aspectj-autoproxy 和使用 aop:config 的配置解析不太一样,具体表现在生成 PointCut 和生成 Before、After、Around 等切面类时,使用 aop:config 的方式会为这些注解生成一个 BeanDefinition,而这个 BeanDefinition 的构造函数是由 3 个 BeanDefinition 组成,表明这个类是合成类,即 synthetic 这个属性为 true。然后跟解析普通的 bean 一样,生成这些实例对象,后面的过程就跟是用纯注解的方式相同了,接下来的分析是基于纯注解分析的,也就是解析从解析 aop:aspectj-autoproxy 这个标签开始。

前面的 xml 文件的标签解析是通过 parseDefaultElement 方法解析默认的 标签的,而我们在配置文件里面配置了启动自动代理的方式 ,当 Spring 读取到这个标签,则会走 parseCustomElement(root) 这个方法了,这个方法的源码不再解析,主要完成的功能如下:

  • 获取 element 的 nameSpaceUri, 根据 nameSpaceUri 找到 NameSpaceHanlder
  • 调用 NameSpaceHanlder 的 parse 方法解析 element

下面是 NameSpaceHanlder 接口的定义:

public interface NamespaceHandler {
    void init();
    BeanDefinition parse(Element element, ParserContext parserContext);
    BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext       parserContext);
}

这里面的 init 方法是我们初始化操作的,这里可以完成对指定的标签设置解析器,然后再 parse 方法里面找到指定标签的解析器,然后调用该解析器的 parse 方法解析标签,后面会重点看这两个方法。

再来看下 Spring 如何加载 NameSpaceHanlder 的,Spring 首先会取查找项目空间下目录 META-INF / 的所有 spring.handlers 文件,这个文件是在 Spring 依赖的 jar 下面,在核心 jar 包都会由这个文件,aop 的 jar 包路径下文件内容为:spring.handlers

http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

发现这里面存储的是一个 key,value,key 是 aop 的 nameSpaceUri,value 是 AopNamespaceHandler,从这个类名上就能发现该类实现了 NamespaceHandler,肯定也就实现了 init 和 parse 方法,所以解析 <aop:aspectj-autoproxy/> 的任务就由 AopNamespaceHandler 的 parse 完成。
查看 AopNamespaceHandler 的 init 方法:

@Override
public void init() {
  // In 2.0 XSD as well as in 2.1 XSD.
  registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
  registerBeanDefinitionParser("aspectj-autoproxy", new                       AspectJAutoProxyBeanDefinitionParser());
  registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
  // Only in 2.0 XSD: moved to context namespace as of 2.1
  registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

上面的代码就很清晰了, 标签由 ConfigBeanDefinitionParser 处理, 则由 AspectJAutoProxyBeanDefinitionParser 这个类处理,这两种处理其实对应了自动代理和通过 xml 配置的处理方式,然后会调用 AspectJAutoProxyBeanDefinitionParser 的 parse 方法:

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    extendBeanDefinition(element, parserContext);
    return null;
}

这个方法其实就是为了注册一个 AnnotationAwareAspectJAutoProxyCreator 类,然后 AOP 的所有处理逻辑都会交给这个类处理,由于这个类的实现了 BeanPostProcessor, 所以这个类的入口就是 BeanPostProcessor 接口的两个方法:

  • postProcessBeforeInitialization
  • postProcessAfterInitialization

    6、Spring Aop 源码解读前奏

    上面分析了,当 spring 读取 xml 文件遇到 会找到 AopNamespaceHandler 这个处理类,然后这个类又将这个标签委托给了 AspectJAutoProxyBeanDefinitionParser 类,最终调用这个类得 parse 方法,parse 方法未做分析,其实这个方法的目的很简单,就是注册 AnnotationAwareAspectJAutoProxyCreator 这个类,这个类实现了 BeanPostProcessor 和 InstantiationAwareBeanPostProcessor 接口,最终在实例化 bean 对象也就是执行 BeanFactory.getBean(beanName) 的过程中,会调用这两个接口的方法 (执行顺序如下):

  • InstantiationAwareBeanPostProcessor 先执行:
    - postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
    - postProcessAfterInstantiation(Object bean, String beanName)

  • BeanPostProcessor 再执行:
    - postProcessBeforeInitialization(Object bean, String beanName)
    - Object postProcessAfterInitialization(Object bean, String beanName)

AOP 的实现基本上是在这两个方法中进行的,所以就从这里来看 Spring 是如何实现 AOP 的,Spring 的 AOP 代理目前支持方法的增强,看源码目前好像也支持了属性的增强了。
读取源码前首先来分析一下方法增强的原理,有助于我们读取源码时紧紧抓住主线。首先第一个问题,如果我们想对一个类的方法进行增强,我们应该怎么做呢?

这种业务需求可以通过代理实现,在方法执行前,拦截这个方法,并且加入要执行增强的逻辑,最后再执行目标方法。下面是 Spring 用的两种代理方式:

  • JDK 代理:我们可以通 Proxy 类获取一个目标类的代理对象,但 JDK 代理要求被代理的类必须实现接口,所以是基于接口的代理。
  • cglib 代理:如果目标类没有接口,使用 cglib 代理,是由 asm 封装的,直接操作类得字节码,效率也很高。

由于在生产业务中,我们不可能对所有的类都执行增强,所以还需要一个选择器,将符合条件的 bean 进行增强,Spring 使用了 PointCut 接口,通过该接口的 getMethodMatcher 方法获取一个方法匹配器,然后通过 matches 方法匹配到目标类对象的目标方法执行增强操作。mathcer 匹配规则就是通过 Spring 配置的 expression 表达式了。

所以在分析源码的时,要围绕这两方面进行:

  • 匹配切点方法(构建切入点表达式类和切面类)
  • 创建代理对象

(1)这两方面在 Spring 的实现里非常复杂,尤其是第一步匹配切点方法过程,这个过程中 Spring 会将 @Aspect 注解类的 @Before,@After,@Around、@Pointcut 等注解都封装成待执行的切面方法类,然后通过方法匹配器匹配到的要增强的方法前后执行切面方法类,达到方法增强的目的。
(2)第二阶段,创建代理对象默认是通过 JDK 代理实现配置, 这样配置可以指定使用 cglib 代理。

10、为切面方法创建 Advice

上面方法的最后一句 instantiateAdvice(this.declaredPointcut) 会创建一个 advice,具体是调用 getAdvice 方法获取:

@Override
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    //获取切面类对象,这里是TracesRecordAdvisor
    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);
    // 核心点1:获取切面注解,这里的方法是 beforePrint 使用了@Before注解
    AspectJAnnotation<?> aspectJAnnotation =
        AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }
    ....................
        AbstractAspectJAdvice springAdvice;
    // 核心点2:根据注解转换后的 将注解生成不同的Advice类。
    switch (aspectJAnnotation.getAnnotationType()) {
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtPointcut:
            //这里对PointCut不做处理
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        default:
            throw new UnsupportedOperationException(
                "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // 将切面类信息配置到SpringAdvice中
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();
    return springAdvice;
}

核心点 1

首先来看看核心点 1,上面其实已经看过了, 但是上面的方法作用仅仅是为了获取注解上的 exression 表达式的,这里再调用一遍就是为注解生成 Advice 类的,目的就是获取切面注解与 AspectJAnnotation 的映射类。

protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    //看到了我们熟悉的切面方法注解,这里的beforePrint使用@Before注解
   Class<?>[] classesToLookFor = new Class<?>[] {
         Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
   for (Class<?> c : classesToLookFor) {
      AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
      if (foundAnnotation != null) {
         return foundAnnotation;
      }
   }
   return null;
}

这个方法就是查找切面方法是否实现了 Before, Around, After,AfterReturning, AfterThrowing,Pointcut 注解,如果实现了,则返回一个 AspectJAnnotation 对象,里面有一个 annotation 的泛型对象,这个泛型对象就是被设置为这些注解的值。最终这些对象会被转换成下面的对象存入 AspectJAnnotation 中:

static {
   //会将注解转换成后面的AspectJAnnotationType枚举的类。 
   annotationTypes.put(Pointcut.class,AspectJAnnotationType.AtPointcut);
   annotationTypes.put(After.class,AspectJAnnotationType.AtAfter);
   annotationTypes.put(AfterReturning.class,AspectJAnnotationType.AtAfterReturning);
   annotationTypes.put(AfterThrowing.class,AspectJAnnotationType.AtAfterThrowing);
   annotationTypes.put(Around.class,AspectJAnnotationType.AtAround);
   annotationTypes.put(Before.class,AspectJAnnotationType.AtBefore);
}

核心点 2

通过核心点 1,Spring 已经将注解 @Before 对应转换为 AtBefore,@After 转换成 AtAfter,以此类推,都会一一映射到了核心点 2 的 switch 的条件类了,在核心点 2 中,会为对应的切面注解类生成 Advice 类。 所有的注解切面类具体实现都是由 AbstractAspectJAdvice 这个抽象类实现的,这个类的构造函数有三个参数:

  • Method aspectJAroundAdviceMethod: 切面方法 这里可能是beforePrint
  • AspectJExpressionPointcut pointcut: 切入点表达式匹配器 这里指封装了exression的匹配器
  • AspectInstanceFactory aif: 切面类 这里指TracesRecordAdvisor

下面是 Spring 为对应注解生成对应的 Advice 类:

注解类 Advice 顾问方法
AtBefore AspectJMethodBeforeAdvice
AtAfter AspectJAfterAdvice
AtAfterReturning AspectJAfterReturningAdvice
AtAfterThrowing AspectJAfterThrowingAdvice
AtAround AspectJAroundAdvice

各个注解会在不同的实际执行自身增强方法,这个部分只是生成 Advice 类,然会放入到缓存中,等真正生成代理时就会调用这些方法。这个在创建代理的时候需要具体拆开说,至此,Spring 将使用了 @Aspect 注解的切面类的切面方法,都转换成了对应的 Adivsor 类,这个类包含了切面方法,封装后的切点匹配器 PointCut 以及生成切面类的实例对象,通过这个类就可以匹配到符合条件的目标类的目标方法,然后执行增强操作了。

由切面注解生成的 Advice 类,最终会放入到一个缓存中,当生成目标 bean 的时候,会将所有所以能够匹配到目标 bean 的 advice 放入到集合中,由一个实现了 MethodInvocation 的类统一管理调用过程,这个类后面会详细说到,这里简单分析下 AspectJAfterAdvice 的 invoke 方法,看看它的调用过程

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        //调用是实现了MethodInvocation方法的类 这个其实是个链式调用
        return mi.proceed();
    }
    finally {
        //最终执行后置增强方法
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
}

上面的 invoke 方法需要一个 MethodInvocation 的参数,上面的 Advice 类除了 AspectJMethodBeforeAdvice 之外,都实现了这个接口,所以可以实现链式调用,这个逻辑会在创建代理的具体讲解,这里只是简单分析下,这些 advice 的 invoke 方法规定了切面方法于要增强方法的执行时机。

11、AOP 代理初窥

上面一部分操作主要是处理使用了 @Aspect 注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应的 Advisor 的过程,这个 Advisor 包含了切面方法,切入点匹配器和切面类,也就是准好了要增强的逻辑,接下来就是要将这些逻辑注入到合适的位置进行增强,这部分的操作就是由老生常谈的代理实现的了。

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
       //如果要创建的类不是提前暴露的代理 则进入下面的方法
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

创建代理前,需要先校验 bean 是否需要创建代理

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //如果bean是通过TargetSource接口获取 则直接返回
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
    //如果bean是切面类 直接返回
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
    //如果bean是Aspect 而且允许跳过创建代理, 加入advise缓存 返回
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }
   //如果前面生成的advisor缓存中存在能够匹配到目标类方法的Advisor 则创建代理
   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;
}

方法很简单,主要的关注点在 getAdvicesAndAdvisorsForBean 和 createProxy 上,第一个是获取能够匹配目标类方法的 Advisor 集合,如果这个集合不为空,则代表该类需要被增强,需要生成代理,如果匹配不到,则表示该类并不需要被增强,无需创建代理。至于 createProxy 就很明显了,就是创建代理,这个方法里面决定了使用 jdk 代理还是 cglib 代理,并且用到了前面生成的 Advisor 实现增强功能。 这部分内容会放到下一篇文章中专门分析。

12、简单总结

简单总结一下,Spring AOP 在第一阶段完成的主要任务:
读取配置文件阶段:

  • 读取 xml 文件遇到 标签时,找到命名空间处理器 AopNamespaceHandler, 然后找到处理该标签的类 AspectJAutoProxyBeanDefinitionParser
  • 通过 AspectJAutoProxyBeanDefinitionParser 的 parse 方法,将 AspectJAwareAdvisorAutoProxyCreator 注册到容器的声明周期中。

创建 bean 阶段:

  • 执行 AspectJAwareAdvisorAutoProxyCreator 的 postProcessBeforeInstantiation 校验目标类是否是 Aspect 类和 AOP 基础类以及是否需要跳过不需要执行代理的类
  • 获取 beanDefinitions 中所有使用了 Aspect 注解的类,然后将切面方法根据使用的注解生成 Advisor 类放入到缓存(关键)
  • 调用 AspectJAwareAdvisorAutoProxyCreator 的 postProcessAfterInitialization 的方法,对需要增强的类创建代理。

这个就是 Spring AOP 在这个阶段所完成的工作,下一部分将专门针对 Spring 如何实现 jdk 和 cglib 代理分析。