一. AOP切面源码分析

源码分析分为三部分

1. 解析切面

2. 创建动态代理

3. 调用


  • 源码的入口
  1. 源码分析的入口, 从注解开始:
  2. 组件的入口是一个注解, 比如启用AOP的注解@EnableAspectJAutoProxy. 在注解的实现类里面, 会有一个@Import(""). 这个@Import("")就是引入的源码实现类. 比如AOP@Import(AspectJAutoProxyRegistrar.class)
  1. 通常, Spring要开启某一个功能, 都会增加一个注解, 如果我们再想要看某一个功能的源码, 那么就可以从他的注解跟进去看,在找到@Import("")就找到源码的入口了

源码分析的入口, AOP注解:

  1. package com.lxl.www.aop;
  2.  
  3. import org.springframework.beans.factory.annotation.Configurable;
  4. import org.springframework.context.annotation.ComponentScan;
  5. import org.springframework.context.annotation.EnableAspectJAutoProxy;
  6.  
  7. @Configurable
  8. // 使用注解的方式引入AOP
  9. @EnableAspectJAutoProxy
  10. @ComponentScan("com.lxl.www.aop")
  11. public class MainConfig {
  12.  
  13. }

引入AOP, 我们需要在配置文件中增加@EnableAspectJAutoProxy代理. 那么想要去掉AOP的引入, 只需要将这个注解注释掉就可以了.  这个注解解释整个AOP的入口.

提示: 其他组件的引入也是类似的, 通常引入组件, 需要增加一个注解, 而整个功能的入口就在这个主机上面.

接下来, 进入到注解类

  1. package org.springframework.context.annotation;
  2.  
  3. import java.lang.annotation.Documented;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8.  
  9. @Target(ElementType.TYPE)
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Documented
  12. @Import(AspectJAutoProxyRegistrar.class)
  13. public @interface EnableAspectJAutoProxy {
  14.  
  15. boolean proxyTargetClass() default false;
  16.  
  17. boolean exposeProxy() default false;
  18.  
  19. }

这是, 我们看到EnableAspectJAutoProxy类增加了一个@Import注解类, 我们知道Import注解可以向IoC容器中增加一个bean.

下面进入到AspectJAutoProxyRegistrar类

  1. package org.springframework.context.annotation;
  2.  
  3. import org.springframework.aop.config.AopConfigUtils;
  4. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  5. import org.springframework.core.annotation.AnnotationAttributes;
  6. import org.springframework.core.type.AnnotationMetadata;
  7.  
  8. class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
  9.  
  10. /**
  11. * Register, escalate, and configure the AspectJ auto proxy creator based on the value
  12. * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
  13. * {@code @Configuration} class.
  14. */
  15. @Override
  16. public void registerBeanDefinitions(
  17. AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  18.     
  19. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
  20.  
  21. AnnotationAttributes enableAspectJAutoProxy =
  22. AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
  23. if (enableAspectJAutoProxy != null) {
  24. if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
  25. AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  26. }
  27. if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
  28. AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
  29. }
  30. }
  31. }
  32.  
  33. }

我们看到, 使用ImportBeanDefinitionRegistrar注册了一个BeanDefinition.

需要记住的是, 通常使用ImportBeanDefinitionRegistrar结合@Import可以向容器中注册一个BeanDefinition.

如何注册的呢? 看具体实现.

  1. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

注册名字是internalAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator

  1. @Nullable
  2. public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
  3. BeanDefinitionRegistry registry, @Nullable Object source) {
  4.  
  5. /**
  6. * 注册一个AnnotationAwareAspectJAutoProxyCreator类型的bean定义
  7. */
  8. return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
  9. }

如上结构梳理如下:

我们看到,  注册了类AnnotationAwareAspectJAutoProxyCreator类型的bean. 这是一个什么样的类呢? 我们来看一下类的结构. 这个类的继承结构很庞大, 我们只看和本次内容相关的继承结构

解析切面, 创建动态代理, 都是在bean的后置处理器中进行的, 下面对照着AOP的实现原理以及createBean(创建bean)的过程来看

上图是bean加载过程中调用的9次后置处理器. 在创建bean之前调用了InstantiationAwareBeanPostProcessor后置处理器判断是否需要为这个类创建AOP, 也就是解析切面的过程. 所以在AnnotationAwareAspectJAutoProxyCreator里面实现了InstantiationAwareBeanPostProcessor后置处理器的接口. 重写了postProcessBeforeInstantiation方法.

在createBean的第三阶段初始化之后, 要创建AOP的动态代理, 调用了BeanPostProcess后置处理器, AnnotationAwareAspectJAutoProxyCreator也实现了BeanPostProcess接口. 重写了postProcessAfterInitialization.

同时也需要处理AOP的循环依赖的问题, 处理循环依赖是在属性赋值之前调用SmartInstantiationAwareBeanPostProcessor后置处理器, 然后重写getEarlyBeanReference方法. 我们看到AnnotationAwareAspectJAutoProxyCreator也实现了SmartInstantiationAwareBeanPostProcessor接口. 并重写getEarlyBeanReference方法.

1) AOP解析切面 

通过上面的分析,我们知道了, 解析切面是在重写了InstantiationAwareBeanPostProcessor后置处理器的postProcessBeforeInstantiation方法. 所以,我们要找到AnnotationAwareAspectJAutoProxyCreator重写的postProcessBeforeInstantiation方法.

  1. 小贴士
  2.  
  3. 如何找到呢? idea中使用快捷键ctrl + o, 找到当前类重写的所有方法. 在搜索postProcessBeforeInstantiation, 就可以找到了

进入创建动态代理的bean的后置处理器, 这是解析切面的第一个入口

  1. @Override
  2. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
  3. ......
  4. }

我们在postProcessBeforeInstantiation方法的入口处打一个断点,  接下来看一下这个接口的调用链

如上图, 可以看出我们的入口是main方法, 然后调用了refresh()方法, 执行的是refresh()方法的finishBeanFactoryInitialization()方法, 然胡调用了doGetBean()下的createBean().然后调用的是resolveBeforeInstantiation的applyBeanPostProcessorsBeforeInstantiation方法,在这里获取到所有的bean的后置处理器, 判断这个bean的后置处理器是否是InstantiationAwareBeanPostProcessor的一个实例. 如果是, 那么就调用postProcessBeforeInstantiation()方法. 

  1. @Nullable
  2. protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
  3. /**
  4. * 获取容器中所有的后置处理器
  5. * 这之前有一个注册bean定义的方法, 已经注册过了. 所以在这里可以获取到列表
  6. *
  7. * 9次bean的后置处理器, 都是一个类实现InstantiationAwareBeanPostProcessor类, 重写postProcessBeforeInstantiation方法
  8. */
  9. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  10. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  11. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  12. Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
  13. if (result != null) {
  14. return result;
  15. }
  16. }
  17. }
  18. return null;
  19. }

下面就来分析postProcessBeforeInstantiation()方法

  1. @Override
  2. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
  3. /**
  4. * 在第一个bean创建的时候, 就会去调用所有的bean的后置处理器, 并且解析所有的切面.
  5. * 这一步是非常消耗性能的. 所以, 会放到缓存当中
  6. */
  7. // 构建缓存的key
  8. Object cacheKey = getCacheKey(beanClass, beanName);
  9.  
  10. // 没有beanName或者不包含在targetSourcedBeans
  11. if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
  12. // 判断是否已经被解析过?
  13. if (this.advisedBeans.containsKey(cacheKey)) {
  14. // 解析过, 则直接返回
  15. return null;
  16. }
  17. /*
  18. * 判断当前这个类是不是需要跳过的类.如果是基础类或者是应该跳过里的类, 则返回null, 表示这个类不需要被解析
  19. *
  20. * 判断是不是基础bean(是不是切面类, 通知, 切点). 因为如果类本身是一个通知, 切面, 那我们不需要解析它
  21. * 跳过的类: 默认是false. 在shouldSkip里面拿到所有的bean定义, 标记是不是@Aspect, 然后将每一个通知生成一个advisor
  22. */
  23. if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
  24. /**
  25. * advisedBean是一个集合, 用来保存类是否是一个advise
  26. */
  27. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  28. return null;
  29. }
  30. }
  31.  
  32. // Create proxy here if we have a custom TargetSource.
  33. // Suppresses unnecessary default instantiation of the target bean:
  34. // The TargetSource will handle target instances in a custom fashion.
  35. TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  36. if (targetSource != null) {
  37. if (StringUtils.hasLength(beanName)) {
  38. this.targetSourcedBeans.add(beanName);
  39. }
  40. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
  41.  
  42. // 创建了代理
  43. Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
  44. this.proxyTypes.put(cacheKey, proxy.getClass());
  45. return proxy;
  46. }
  47.  
  48. return null;
  49. }

第一步: 构建缓存

  1. 构建缓存的key
  2. Object cacheKey = getCacheKey(beanClass, beanName);
  1. 在第一个bean创建的时候, 就会去调用所有的bean的后置处理器, 并且解析所有的切面.
    这一步是非常消耗性能的. 所以, 会放到缓存当中. 已经创建过的,后面将不再创建

第二步: 校验bean是否被解析过. 如果已经解析过, 则不再解析

  1. // 判断是否已经被解析过
  2. if (this.advisedBeans.containsKey(cacheKey)) {
  3. // 解析过, 则直接返回
  4. return null;
  5. }

第三步: 判断类是否是需要跳过的类

  1. if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
  2. /**
  3. * advisedBean是一个集合, 用来保存类是否是一个advise
  4. */
  5. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  6. return null;
  7. }

如果是基础类或者是应该跳过的类, 则返回null, 表示这个类不需要被解析.

这里有两个判断.

isInfrastructureClass(beanClass) 判断当前这个类是不是基础类, 这里的基础类的含义如下: Advice、Pointcut、Advisor、AopInfrastructureBean。如果本身就是基础类,那么不用在解析了

  1. protected boolean isInfrastructureClass(Class<?> beanClass) {
  2. // 如果这个类是一个Advice类型的类, 或者 Pointcut类型的类, 或者Adivsor类型的类, 或者AOPInsfrastructureBean类型的类.
  3. boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
  4. Pointcut.class.isAssignableFrom(beanClass) ||
  5. Advisor.class.isAssignableFrom(beanClass) ||
  6. AopInfrastructureBean.class.isAssignableFrom(beanClass);
  7. if (retVal && logger.isTraceEnabled()) {
  8. logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
  9. }
  10. return retVal;
  11. }

shouldSkip(beanClass, beanName)判断当前是否是需要跳过的类 .

  1. @Override
  2. protected boolean shouldSkip(Class<?> beanClass, String beanName) {
  3. // 找到候选的Advisors(前置通知, 后置通知等)
  4. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  5. for (Advisor advisor : candidateAdvisors) {
  6. if (advisor instanceof AspectJPointcutAdvisor &&
  7. ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
  8. return true;
  9. }
  10. }
  11. return super.shouldSkip(beanClass, beanName);
  12. }

findCandidateAdvisors(); 找到候选的类, 然后将候选类构造成Advisor对象. 进到方法里看看是如何筛选出候选对象的.

AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()

  1. @Override
  2. protected List<Advisor> findCandidateAdvisors() {
  3. // Add all the Spring advisors found according to superclass rules.
  4. // 找到xml方式配置的Advisor和原生接口的AOP的advisor 以及找到事务相关的advisor
  5. List<Advisor> advisors = super.findCandidateAdvisors();
  6. // Build Advisors for all AspectJ aspects in the bean factory.
  7. // 将找到的aspect, 封装为一个Advisor
  8. if (this.aspectJAdvisorsBuilder != null) {
  9. //buildAspectJAdvisors()方法就是用来解析切面类, 判断是否含有@Aspect注解, 然后将每一个通知生成一个advisor
  10. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  11. }
  12. // 返回所有的通知
  13. return advisors;
  14. }

这里做了两件事

第一步: 解析xml方式配置的Advisor (包括原生接口方式配置的advisor 以及找到事务相关的advisor)

第二步: 解析注解方式的切面. buildAspectJAdvisors()方法是用来解析切面类的. 解析每一个切面类中的通知方法, 并为每个方法匹配切点表达式.

  1. public List<Advisor> buildAspectJAdvisors() {
  2. /*
  3. * aspectNames: 用于保存切面名称的集合
  4. * aspectNames是缓存的类级别的切面, 缓存的是已经解析出来的切面信息
  5. */
  6. List<String> aspectNames = this.aspectBeanNames;
  7. // 如果aspectNames值为空, 那么就在第一个单例bean执行的时候调用后置处理器(AnnotationAwareAspectJAutoProxy)
  8. if (aspectNames == null) {
  9. // 加锁, 防止多个线程, 同时加载 Aspect
  10. synchronized (this) {
  11. aspectNames = this.aspectBeanNames;
  12. // 双重检查
  13. if (aspectNames == null) {
  14. // 保存所有从切面中解析出来的通知
  15. List<Advisor> advisors = new ArrayList<>();
  16. // 保存切面名称的集合
  17. aspectNames = new ArrayList<>();
  18. /*
  19. * 扫描Object的子类. 那就是扫描所有的类
  20. *
  21. * 这里传入要扫描的对象是Object.class. 也就是说去容器中扫描所有的类.
  22. * 循环遍历. 这个过程是非常耗性能的, 所以spring增加了缓存来保存切面
  23. *
  24. * 但事务功能除外, 事务模块是直接去容器中找到Advisor类型的类 选择范围小
  25. * spring 没有给事务模块加缓存
  26. */
  27. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  28. this.beanFactory, Object.class, true, false);
  29. // 循环遍历beanNames
  30. for (String beanName : beanNames) {
  31. if (!isEligibleBean(beanName)) {
  32. continue;
  33. }
  34. // We must be careful not to instantiate beans eagerly as in this case they
  35. // would be cached by the Spring container but would not have been weaved.
  36. // 通过beanName去容器中获取到对应class对象
  37. Class<?> beanType = this.beanFactory.getType(beanName);
  38. if (beanType == null) {
  39. continue;
  40. }
  41. // 判断bean是否是一个切面, 也就是脑袋上是否有@Aspect注解
  42. if (this.advisorFactory.isAspect(beanType)) {
  43. aspectNames.add(beanName);
  44. // 将beanName和class对象构建成一个AspectMetadata对象
  45. AspectMetadata amd = new AspectMetadata(beanType, beanName);
  46. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
  47. MetadataAwareAspectInstanceFactory factory =
  48. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
  49. // 解析切面类中所有的通知--一个通知生成一个Advisor.
  50. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
  51. // 加入到缓存中
  52. if (this.beanFactory.isSingleton(beanName)) {
  53. this.advisorsCache.put(beanName, classAdvisors);
  54. } else {
  55. this.aspectFactoryCache.put(beanName, factory);
  56. }
  57. advisors.addAll(classAdvisors);
  58. } else {
  59. // Per target or per this.
  60. if (this.beanFactory.isSingleton(beanName)) {
  61. throw new IllegalArgumentException("Bean with name '" + beanName +
  62. "' is a singleton, but aspect instantiation model is not singleton");
  63. }
  64. MetadataAwareAspectInstanceFactory factory =
  65. new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
  66. this.aspectFactoryCache.put(beanName, factory);
  67. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  68. }
  69. }
  70. }
  71. this.aspectBeanNames = aspectNames;
  72. return advisors;
  73. }
  74. }
  75. }
  76.  
  77. if (aspectNames.isEmpty()) {
  78. return Collections.emptyList();
  79. }
  80. List<Advisor> advisors = new ArrayList<>();
  81. for (String aspectName : aspectNames) {
  82. List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
  83. if (cachedAdvisors != null) {
  84. advisors.addAll(cachedAdvisors);
  85. } else {
  86. MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
  87. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  88. }
  89. }
  90. return advisors;
  91. }

我们来看看如何生成List<Advisor>的

  1. // 解析切面类中所有的通知--一个通知生成一个Advisor.
  2. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
  1. public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
  2. // 获取标记了@Aspect的类
  3. Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  4. // 获取切面类的名称
  5. String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
  6. // 验证切面类
  7. validate(aspectClass);
  8.  
  9. // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
  10. // so that it will only instantiate once.
  11. // 使用包装的模式来包装 aspectInstanceFactory, 构建成MetadataAwareAspectInstanceFactory类
  12. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
  13. new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
  14.  
  15. // 通知的集合, 按照排序后
  16. List<Advisor> advisors = new ArrayList<>();
  17. // 获取切面类中所有的通知方法, 除了带有@Pointcut注解的方法
  18. for (Method method : getAdvisorMethods(aspectClass)) {
  19. // 将候选方法解析为Advisor. Advisor中包含advise和pointcut. 注意: getAdvisor()方法中定义了切面解析的顺序
  20. Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
  21. if (advisor != null) {
  22. advisors.add(advisor);
  23. }
  24. }
  25.  
  26. // If it's a per target aspect, emit the dummy instantiating aspect.
  27. if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  28. Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
  29. advisors.add(0, instantiationAdvisor);
  30. }
  31.  
  32. // Find introduction fields.
  33. for (Field field : aspectClass.getDeclaredFields()) {
  34. Advisor advisor = getDeclareParentsAdvisor(field);
  35. if (advisor != null) {
  36. advisors.add(advisor);
  37. }
  38. }
  39.  
  40. return advisors;
  41. }

这里主要有两点, 第一个是getAdvisorMethods(aspectClass)获取当前切面类的所有的AdvisorMethod , 第二个是封装成的Advisor对象

  • 第一步: 解析切面类中所有的通知方法.getAdvisorMethods(aspectClass)

    1. /**
    2. * 获取切面类中所有的方法, 且方法中有@Pointcut注解
    3. * @param aspectClass
    4. * @return
    5. */
    6. private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    7. final List<Method> methods = new ArrayList<>();
    8. // 调用doWithMethods. 第二个参数是一个匿名函数, 重写了doWith方法
    9. ReflectionUtils.doWithMethods(aspectClass, method -> {
    10. // 解析切面类中所有的方法, 除了Pointcut
    11. if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
    12. methods.add(method);
    13. }
    14. }, ReflectionUtils.USER_DECLARED_METHODS);
    15. if (methods.size() > 1) {
    16. // 对方法进行排序
    17. methods.sort(METHOD_COMPARATOR);
    18. }
    19. return methods;
    20. }

这个方法是, 扫描切面类的所有方法, 将其添加到methods中, 除了Pointcut注解的方法

然后对methods进行排序, 如何排序呢?

  1. private static final Comparator<Method> METHOD_COMPARATOR;
  2.  
  3. static {
  4. Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
  5. new InstanceComparator<>(
  6. Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
  7. (Converter<Method, Annotation>) method -> {
  8. AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
  9. return (ann != null ? ann.getAnnotation() : null);
  10. });
  11. Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
  12. METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
  13. }

按照Aroud, Before, After, AferReturning, AfterThrowing的顺序对通知方法进行排序

  • 第二步: 将候选的方法解析为Advisor. 这里也是有两步.具体如下:

    1. /**
    2. * 解析切面类中的方法
    3. * @param candidateAdviceMethod 候选的方法
    4. */
    5. @Override
    6. @Nullable
    7. public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
    8. int declarationOrderInAspect, String aspectName) {
    9.  
    10. validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    11.  
    12. // 获取切面中候选方法的切点表达式
    13. AspectJExpressionPointcut expressionPointcut = getPointcut(
    14. candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    15. if (expressionPointcut == null) {
    16. return null;
    17. }
    18.  
    19. // 将切点表达式和通知封装到InstantiationModelAwarePointcutAdvisorImpl对象中, 这是一个Advisor通知
    20. return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
    21. this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    22. }

在getPointcut中解析了method,以及切点表达式pointcut

  1. /**
  2. * 找到候选方法method属于哪一种类型的Aspectj通知
  3. * @param candidateAdviceMethod 候选的通知方法
  4. * @param candidateAspectClass 候选的切面类
  5. * @return
  6. */
  7. @Nullable
  8. private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  9. // 第一步: 解析候选方法上的注解,类似@Before(value="pointcut()")
  10. // 找到Aspectj注解: @Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing
  11. AspectJAnnotation<?> aspectJAnnotation =
  12. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  13. if (aspectJAnnotation == null) {
  14. return null;
  15. }
  16.  
  17. // 第二步: 解析aspect切面中的切点表达式
  18. AspectJExpressionPointcut ajexp =
  19. new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  20. // 解析切点表达式
  21. ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  22. if (this.beanFactory != null) {
  23. ajexp.setBeanFactory(this.beanFactory);
  24. }
  25. return ajexp;
  26. }

如上代码, 可知, 这里也是有两个操作. 分别是将method解析为Advise, 另一个是解析切面类中的pointcut切点表达式. 返回返回切点表达式.

接下来, 就是将候选方法和切点表达式封装成Advisor. 在getAdvisor(...)方法中:

  1. // 将切点表达式和通知封装到InstantiationModelAwarePointcutAdvisorImpl对象中, 这是一个Advisor通知
  2. return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
  3. this, aspectInstanceFactory, declarationOrderInAspect, aspectName);

expressionPointcut: 即切点表达式; candidateAdviceMethod: 即候选方法

  1. public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
  2. Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
  3. MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  4.  
  5. // 当前的切点
  6. this.declaredPointcut = declaredPointcut;
  7. // 切面类
  8. this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
  9. // 切面方法名
  10. this.methodName = aspectJAdviceMethod.getName();
  11. //切面方法参数的类型
  12. this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
  13. //切面方法对象
  14. this.aspectJAdviceMethod = aspectJAdviceMethod;
  15. // aspectJ的通知工厂
  16. this.aspectJAdvisorFactory = aspectJAdvisorFactory;
  17. // aspectJ的实例工厂
  18. this.aspectInstanceFactory = aspectInstanceFactory;
  19. // advisor的顺序
  20. /**
  21. * 前面我们看到, Advisor会进行排序, Around, Before, After, AfterReturning, AfterThrowing, 按照这个顺序.
  22. * 那么order值是什么呢?是advisors的size. 如果size是0, 那么就是第一个方法. 这里第一个不一定是Around, 他可能没有Around通知, 也没有Before通知.
  23. */
  24. this.declarationOrder = declarationOrder;
  25. // 切面名
  26. this.aspectName = aspectName;
  27.  
  28. if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  29. // Static part of the pointcut is a lazy type.
  30. Pointcut preInstantiationPointcut = Pointcuts.union(
  31. aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
  32.  
  33. this.pointcut = new PerTargetInstantiationModelPointcut(
  34. this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
  35. this.lazy = true;
  36. }
  37. else {
  38. // A singleton aspect.
  39. this.pointcut = this.declaredPointcut;
  40. this.lazy = false;
  41. this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
  42. }
  43. }

前面已经得到了切入点表达式, 这里会进行初始化Advice, 初始化的时候, 根据通知的类型进行初始化.

  • 环绕通知, 构建一个环绕通知的对象
  • 前置通知, 构建一个前置通知的对象
  • 后置通知, 构建一个后置通知的对象
  • 异常通知, 构建一个异常通知的对象
  • 返回通知, 构建一个返回通知的对象

具体代码如下:

  1. @Override
  2. @Nullable
  3. public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
  4. MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  5. // 候选的切面类
  6. Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  7. validate(candidateAspectClass);
  8. // 通知方法上的注解内容
  9. AspectJAnnotation<?> aspectJAnnotation =
  10. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  11. if (aspectJAnnotation == null) {
  12. return null;
  13. }
  14.  
  15. // If we get here, we know we have an AspectJ method.
  16. // Check that it's an AspectJ-annotated class
  17. if (!isAspect(candidateAspectClass)) {
  18. throw new AopConfigException("Advice must be declared inside an aspect type: " +
  19. "Offending method '" + candidateAdviceMethod + "' in class [" +
  20. candidateAspectClass.getName() + "]");
  21. }
  22.  
  23. if (logger.isDebugEnabled()) {
  24. logger.debug("Found AspectJ method: " + candidateAdviceMethod);
  25. }
  26.  
  27. AbstractAspectJAdvice springAdvice;
  28.  
  29. switch (aspectJAnnotation.getAnnotationType()) {
  30. case AtPointcut:
  31. if (logger.isDebugEnabled()) {
  32. logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
  33. }
  34. return null;
  35. case AtAround:
  36. // 封装成环绕通知的对象
  37. springAdvice = new AspectJAroundAdvice(
  38. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  39. break;
  40. case AtBefore:
  41. // 封装成前置通知对象
  42. springAdvice = new AspectJMethodBeforeAdvice(
  43. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  44. break;
  45. case AtAfter:
  46. // 封装成后置通知对象
  47. springAdvice = new AspectJAfterAdvice(
  48. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  49. break;
  50. case AtAfterReturning:
  51. // 封装成返回通知对象
  52. springAdvice = new AspectJAfterReturningAdvice(
  53. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  54. AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
  55. if (StringUtils.hasText(afterReturningAnnotation.returning())) {
  56. springAdvice.setReturningName(afterReturningAnnotation.returning());
  57. }
  58. break;
  59. case AtAfterThrowing:
  60. // 封装异常通知对象
  61. springAdvice = new AspectJAfterThrowingAdvice(
  62. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  63. AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
  64. if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
  65. springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
  66. }
  67. break;
  68. default:
  69. throw new UnsupportedOperationException(
  70. "Unsupported advice type on method: " + candidateAdviceMethod);
  71. }
  72.  
  73. // Now to configure the advice...
  74. springAdvice.setAspectName(aspectName);
  75. springAdvice.setDeclarationOrder(declarationOrder);
  76. String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
  77. if (argNames != null) {
  78. springAdvice.setArgumentNamesFromStringArray(argNames);
  79. }
  80. springAdvice.calculateArgumentBindings();
  81.  
  82. return springAdvice;
  83. }

这就是我们在之前的结构中说过的, 在解析切面的时候, 会解析切面中的每一个方法, 将其解析成一个Advisor, 而每一个Advisor都包含两个部分:Advise和pointcut.

最后, 将所有的切面类都解析完, 将所有的Advisor放入到集合advisors中返回.

这样就完成了切面的解析.

2) 调用动态代理

在ioc解析的过程中, 是在什么时候创建动态代理的呢?

通常是在创建bean初始化之后创建动态代理. 如果有循环依赖, 会在实例化之后创建动态代理, 再来感受一下创建bean过程中的操作.

下面我们来看正常的流程, 在初始化之后创建AOP动态代理 .

在创建bean的过程中,一共有三步, 来看看AbstractAutowireCpableBeanFactory.doCreateBean()

  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  2. throws BeanCreationException {
  3.  
  4. // Instantiate the bean.
  5. BeanWrapper instanceWrapper = null;
  6. if (mbd.isSingleton()) {
  7. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  8. }
  9. if (instanceWrapper == null) {
  10. //第一步: 实例化
  11. instanceWrapper = createBeanInstance(beanName, mbd, args);
  12. }
  13. // 这里使用了装饰器的设计模式
  14. final Object bean = instanceWrapper.getWrappedInstance();
  15. Class<?> beanType = instanceWrapper.getWrappedClass();
  16. ......
  17. try {
  18. // 第二步:填充属性, 给属性赋值(调用set方法) 这里也是调用的后置处理器
  19. populateBean(beanName, mbd, instanceWrapper);
  20. // 第三步: 初始化.
  21. exposedObject = initializeBean(beanName, exposedObject, mbd);
  22. }
  23. ......
  24. }

在第三步初始化的时候, 要处理很多bean的后置处理器.

  1. @Override
  2. public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
  3. throws BeansException {
  4.  
  5. Object result = existingBean;
  6. for (BeanPostProcessor processor : getBeanPostProcessors()) {
  7. Object current = processor.postProcessAfterInitialization(result, beanName);
  8. if (current == null) {
  9. return result;
  10. }
  11. result = current;
  12. }
  13. return result;
  14. }

postProcessAfterInitialization(result, beanName);就是处理初始化之后的后置处理器, 下面就从这个方法作为入口分析.

AnnotationAwareAspectJAutoProxyCreator也实现了postProcessAfterInitialization(result, beanName);接口

  1. @Override
  2. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  3. /**
  4. * 每一个bean在解析的时候都会解析一遍切面.
  5. * 为什么每次都要解析一遍呢? 因为还有另外一种方式-实现Advisor接口的方式实现AOP, 在加载过程中, 可能随时有新的bean被解析出来. 所以, 需要每次都重新解析一遍,.
  6. * 我们在第一次解析的Advisor都已经放入到缓存, 在这里会先从缓存中取, 也就是已经解析过的不会重复解析. 也就是不 消耗性能
  7. */
  8. if (bean != null) {
  9. // 获取缓存key
  10. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  11. /**
  12. * 因为有可能在循环依赖处理的时候已经创建国一遍, 如果是那么现在就不再创建了,并且删除
  13. * 在这里, 我们要处理的是普通类的动态代理, 所以, 需要将循环以来创建的动态代理删掉
  14. */
  15. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  16. // 该方法将返回动态代理的实例
  17. return wrapIfNecessary(bean, beanName, cacheKey);
  18. }
  19. }
  20. return bean;
  21. }
这里需要强调的一点是, 每一个bean在解析的时候都会解析一遍切面.为什么每次都要解析一遍呢?
因为创建切面有两种方式, 一种是实现Advisor接口, 另一种是注解的方式. 实现Advisor接口的方式, 在加载过程中, 可能随时有新的bean被解析出来. 所以, 需要每次都重新解析一遍.
我们在第一次解析的Advisor都已经放入到缓存, 在这里会先从缓存中取, 也就是已经解析过的不会重复解析. 也就是不 消耗性能

接下来处理的流程如下:

这里,第三步:删除循环依赖创建的动态代理对象, 为什么要这样处理呢?

因为有可能在循环依赖处理的时候已经创建了动态代理bean, 如果是,那么现在就不再创建了,并且将其删除. 
在这里, 我们要处理的是普通类的动态代理, 所以, 需要将循环依赖创建的动态代理删掉
 
注: earlyProxyReferences对象使用来存储循环依赖过程中创建的动态代理bean. 如果循环依赖创建了这个代理bean, 那么直接返回, 如果没有创建过, 我们再创建.
 
下面来看看是如何创建的?

  1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  2. // 已经被处理过(解析切面的时候, targetSourcedBeans用来存储自己实现创建动态代理的逻辑)
  3. if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
  4. return bean;
  5. }
  6. // 判断bean是否是需要增强的bean
  7. /**
  8. * 哪些类是不需要增强的呢?
  9. * 在解析切面的时候, 基础类和应该跳过的类是不需要增强的.
  10. */
  11. if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
  12. return bean;
  13. }
  14. // 判断是否是基础类, 或者是否是需要跳过的类
  15. if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
  16. // 将其标记为不需要增强的类
  17. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  18. return bean;
  19. }
  20.  
  21. // 匹配Advisor. 根据类匹配advisors, 至少匹配上一个, 才创建动态代理, 否则不创建动态代理
  22. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  23. // 匹配了至少一个advisor, 创建动态代理
  24. if (specificInterceptors != DO_NOT_PROXY) {
  25. this.advisedBeans.put(cacheKey, Boolean.TRUE);
  26. Object proxy = createProxy(
  27. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  28. this.proxyTypes.put(cacheKey, proxy.getClass());
  29. return proxy;
  30. }
  31.  
  32. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  33. return bean;
  34. }
来看看创建流程

首先判断是否是需要跳过的类. 哪些类是需要跳过的类呢?

第一类:基础类. Advice, Pointcut, Advisor, AopInfrastructureBean.

第二类: 原始的接口类, 以.ORIGINAL开头的类

接下来, 匹配Advisor.

  1. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  2. // 第一步: 拿到已经解析出来的advisors(这次是从缓存中获取)
  3. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  4. // 第二步:循环判断advisor能否作用于当前bean(原理: 切点是否命中bean)
  5. List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  6. // 第三步: 对匹配bean的advisor进行增强
  7. extendAdvisors(eligibleAdvisors);
  8. // 第四步: 对匹配bean的advisor进行排序
  9. if (!eligibleAdvisors.isEmpty()) {
  10. eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  11. }
  12. // 返回匹配到的advisors
  13. return eligibleAdvisors;
  14. }

这里经过了四步, 具体详见上述代码及注释.

  • 第一步: 从缓存中拿到已经解析出来的advisors
  • 第二步:循环判断advisor能否作用于当前bean
  • 第三步: 对匹配bean的advisor进行增强
  • 第四步: 对匹配bean的advisor进行排序

这里面的第一步: 从缓存中取出了已经解析出来的advisors集合. 解析方式是从缓存中取出已经解析的advisors

接下来,循环遍历获得到的advisors, 得到每一个advisor. 判断advisor是否是目标bean需要增强的通知.

这里在筛选的时候, 根据切点表达式进行了两次筛选. 第一次粗筛, 第二次是精筛. 整个目标类, 只要有一个类命中切点表达式, 那么这个类就是需要被创建动态代理的类, 返回true.

接下来就是要创建动态代理了. 然后,返回创建的动态代理对象.

下面来看看是如何创建动态代理的.

创建动态代理对象有两种方式: 一种是jdk代理, 一种是cglib代理.

无论是使用xml配置的方式, 还是使用注解的方式, 都有一个参数proxy-target-class, 如果将这个参数设置为true, 表示强制使用cglib代理. 如下所示设置:

  1. 使用注解的方式
  2. @EnableAspectJAutoProxy(proxyTargetClass=true)
  3.  
  4. 使用xml配置的方式
  5. <aop: sapectj-autoproxy proxy-target-class="true"></aop:>

所以在创建动态代理之前, 先解析注解或者配置, 看是否配置了proxy-target-class参数. 如果配置了这个参数,且其值为true, 那么就创建一个cglib代理对象. 否则创建一个JDK代理对象.通常, 我们使用的更多的是spring自己定义的JDK代理对象. 通过Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);创建动态代理

在JDKDynamicAopProxy代理类中有一个invoke()方法. 这个invoke方法, 就是执行代理对象的方法时调用的方法.

该方法是通过反射的方法执行目标类中定义的方法的.

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2.  
  3. }

 3. 调用动态代理.

调用这里有一个非常经典的调用逻辑--调用链.

如上图, 调用链的逻辑是, 调用动态代理方法,比如说div(arg1, arg2), 然后执行调用链中第一个通知advisor1, 然后第一个通知调用第二个通知, 在执行第二个, 以此类推, 当所有的通知执行完, 调用目标方法div(arg1, arg2), 然后返回执行结果. 我们来看看代码的逻辑实现.

如下代码是调用动态代理的代码入口:

  1. public class LxlMainClass {
  2. public static void main(String[] args) {
  3.  
  4. AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
  5.  
  6. Calculate calculate = (Calculate) ctx.getBean("lxlCalculate");
  7. /**
  8. * 上面的calculate, 就是返回的动态代理的类
  9. * 当调用下面的div方法时, 实际上调用的是JdkDynamicAopProxy.invoke(...)方法
  10. */
  11. calculate.div(2, 4);
  12.  
  13. ProgramCalculate programCalculate = (ProgramCalculate) ctx.getBean("lxlCalculate");
  14. String s = programCalculate.toBinary(5);
  15. System.out.println(s);
  16. }
  17. }

我们在main方法中, 获取的Calculate对象, 其实是动态代理生成的对象. 当调用calculate.div(2, 4)方法时, 其实调用的是动态代理的invoke()方法.

  1. @Override
  2. @Nullable
  3. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  4. Object oldProxy = null;
  5. // 设置代理上下文
  6. boolean setProxyContext = false;
  7.  
  8. // 目标源: 也就是目标代理的目标类
  9. TargetSource targetSource = this.advised.targetSource;
  10. Object target = null;
  11.  
  12. try {
  13.  
  14. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
  15. // The target does not implement the equals(Object) method itself.
  16. return equals(args[0]);
  17. }
  18. else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
  19. // The target does not implement the hashCode() method itself.
  20. return hashCode();
  21. }
  22. else if (method.getDeclaringClass() == DecoratingProxy.class) {
  23. // There is only getDecoratedClass() declared -> dispatch to proxy config.
  24. return AopProxyUtils.ultimateTargetClass(this.advised);
  25. }
  26. // 如果方法所在类是一个接口 && 是可分配为Advised类型的方法
  27. else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
  28. method.getDeclaringClass().isAssignableFrom(Advised.class)) {
  29. // Service invocations on ProxyConfig with the proxy config...
  30. return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
  31. }
  32.  
  33. Object retVal;
  34.  
  35. if (this.advised.exposeProxy) {
  36. // 把代理对象暴露在线程变量中.
  37. oldProxy = AopContext.setCurrentProxy(proxy);
  38. // 设置代理的上下文为true
  39. setProxyContext = true;
  40. }
  41.  
  42. // Get as late as possible to minimize the time we "own" the target,
  43. // in case it comes from a pool.
  44. // 获取目标对象
  45. target = targetSource.getTarget();
  46. Class<?> targetClass = (target != null ? target.getClass() : null);
  47.  
  48. // 把aop的advisor全部转化为拦截器, 通过责任链模式依次调用
  49. /**
  50. * 将advisor对象转换为interceptor对象.
  51. *
  52. * 问题: 为什么要将advisor都转化为interceptor拦截器呢?
  53. * 主要还是因为要进行责任链调用. 之前说过, 要想进行责任链调用, 他们要有一个共同的方法.
  54. * 转化为interceptor以后, 这里共同的方法就是invoke().
  55. * beforeAdivsor, afterAdvisor, returningAdvisor, throwingAdvisor. 这几种类型. 只有returningAdvisor和throwingAdvisor会转化为Interceptor.
  56. * 因为beforeAdvisor和adgerAdvisor本身就实现了interceptor接口
  57. */
  58. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  59. // 拦截器链为空
  60. if (chain.isEmpty()) {
  61. // 通过反射直接调用执行目标方法
  62. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  63. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
  64. }
  65. else {
  66. // 创建一个 method invocation 拦截器
  67. MethodInvocation invocation =
  68. new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  69. // Proceed to the joinpoint through the interceptor chain.
  70. // 通过拦截器链调用连接点
  71. retVal = invocation.proceed();
  72. }
  73.  
  74. // Massage return value if necessary.
  75. Class<?> returnType = method.getReturnType();
  76. if (retVal != null && retVal == target &&
  77. returnType != Object.class && returnType.isInstance(proxy) &&
  78. !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
  79. // Special case: it returned "this" and the return type of the method
  80. // is type-compatible. Note that we can't help if the target sets
  81. // a reference to itself in another returned object.
  82. retVal = proxy;
  83. }
  84. else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
  85. throw new AopInvocationException(
  86. "Null return value from advice does not match primitive return type for: " + method);
  87. }
  88. return retVal;
  89. }
  90. finally {
  91. if (target != null && !targetSource.isStatic()) {
  92. // Must have come from TargetSource.
  93. targetSource.releaseTarget(target);
  94. }
  95. if (setProxyContext) {
  96. // Restore old proxy.
  97. AopContext.setCurrentProxy(oldProxy);
  98. }
  99. }
  100. }

 这里有两步很重要:

第一步: 将匹配的advisor转换为Interceptor

第二步: 调用责任链, 执行各类通知

先看第一步: 将匹配的advisor对象转换为interceptor拦截器对象. 为什么要将advisor转换为interceptor拦截器呢?

因为要进行责任链调用. 前面说过, 要想进行责任链调用, 他们要有一个共同的方法. 转化为interceptor以后, 共同的方法就是invoke().

  1. @Override
  2. public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
  3. Advised config, Method method, @Nullable Class<?> targetClass) {
  4.  
  5. // This is somewhat tricky... We have to process introductions first,
  6. // but we need to preserve order in the ultimate list.
  7. AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
  8. // 获取到匹配当前方法的所有advisor
  9. Advisor[] advisors = config.getAdvisors();
  10. List<Object> interceptorList = new ArrayList<>(advisors.length);
  11. Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
  12. Boolean hasIntroductions = null;
  13.  
  14. for (Advisor advisor : advisors) {
  15. /**
  16. * 如果advisor是PointcutAdvisor类型
  17. */
  18. if (advisor instanceof PointcutAdvisor) {
  19. // Add it conditionally.
  20. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
  21. // 注解配置信息是一个前置过滤器 或者 目标类匹配advisor的切点表达式
  22. if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
  23. MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
  24. boolean match;
  25. if (mm instanceof IntroductionAwareMethodMatcher) {
  26. if (hasIntroductions == null) {
  27. hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
  28. }
  29. match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
  30. }
  31. else {
  32. match = mm.matches(method, actualClass);
  33. }
  34. if (match) {
  35. // 将advice转换为MethodInterceptor拦截器,
  36. MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
  37. if (mm.isRuntime()) {
  38. // Creating a new object instance in the getInterceptors() method
  39. // isn't a problem as we normally cache created chains.
  40. for (MethodInterceptor interceptor : interceptors) {
  41. // 将MethodInterceptor拦截器和MethodMatcher组装为一个新的对象
  42. interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
  43. }
  44. }
  45. else {
  46. // 将拦截器直接放到interceptorList中
  47. interceptorList.addAll(Arrays.asList(interceptors));
  48. }
  49. }
  50. }
  51. }
  52. else if (advisor instanceof IntroductionAdvisor) { // 如果advisor是IntroductionAdvisor类型
  53. IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
  54. if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
  55. Interceptor[] interceptors = registry.getInterceptors(advisor);
  56. interceptorList.addAll(Arrays.asList(interceptors));
  57. }
  58. }
  59. else { // 其他类型的advisor
  60. Interceptor[] interceptors = registry.getInterceptors(advisor);
  61. interceptorList.addAll(Arrays.asList(interceptors));
  62. }
  63. }
  64.  
  65. return interceptorList;
  66. }

这里最重要的方法就是registry.getInterceptors(advisor), 在getInterceptors(advisor)里面循环遍历了advisors, 然后将每一个advisor转换为Interceptor, 这是将advisor转换为interceptor的具体实现.

我们来看看源码和逻辑

  1. @Override
  2. public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
  3. List<MethodInterceptor> interceptors = new ArrayList<>(3);
  4. Advice advice = advisor.getAdvice();
  5. if (advice instanceof MethodInterceptor) {
  6. // 如果advice已经实现了MethodInterceptor接口, 那么直接将其添加到interceptors集合中
  7. interceptors.add((MethodInterceptor) advice);
  8. }
  9. for (AdvisorAdapter adapter : this.adapters) {
  10. // 判断是否是指定类型的advice
  11. if (adapter.supportsAdvice(advice)) {
  12. // 如果是就将其转换为对应类型的Interceptor
  13. interceptors.add(adapter.getInterceptor(advisor));
  14. }
  15. }
  16. if (interceptors.isEmpty()) {
  17. throw new UnknownAdviceTypeException(advisor.getAdvice());
  18. }
  19. return interceptors.toArray(new MethodInterceptor[0]);
  20. }

adapter.supportsAdvice(advice)判断advice是否是指定类型的adapter. adapter有如下几种

  • MethodBeforeAdviceAdapter : 前置通知adapter
  • AfterReturningAdviceAdapter:后置|放回通知adapter
  • SimpleBeforeAdviceAdapter: simpler前置通知adapter
  • ThrowsAdviceAdapter:异常通知adapter

这里采用的是适配器模式, 通过适配器来匹配各种不同类型的通知. 然后再调用adapter.getInterceptor(advisor)将advisor构建成Interceptor.

通常有beforeAdivsor, afterAdvisor, returningAdvisor, throwingAdvisor几种类型的通知. 只有returningAdvisor和throwingAdvisor会转化为Interceptor.
因为beforeAdvisor和afterAdvisor本身就实现了interceptor接口.

将所有的advisor转换成Interceptor以后放入到interceptors集合中返回.

接下来执行责任链调用.责任链调用的思想主要有两个

1. 递归调用

2. 所有的advisor最终都让其实现interceptor, 并重写invoke()方法.

来看一下源码

  1. @Override
  2. @Nullable
  3. public Object proceed() throws Throwable {
  4. // We start with an index of -1 and increment early.
  5. // 如果是最后一个拦截器, 则直接执行. invokeJoinpoint()方法
  6. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  7. return invokeJoinpoint();
  8. }
  9.  
  10. // 取出interceptorsAndDynamicMethodMatchers对象
  11. Object interceptorOrInterceptionAdvice =
  12. this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  13. // 如果是InterceptorAndDynamicMethodMatcher类型
  14. if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  15. // Evaluate dynamic method matcher here: static part will already have
  16. // been evaluated and found to match.
  17. InterceptorAndDynamicMethodMatcher dm =
  18. (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  19. Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
  20. // 调用methodMather的matchs()方法
  21. if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
  22. // 匹配成功, 则调用拦截器的invoke()方法
  23. return dm.interceptor.invoke(this);
  24. }
  25. else {
  26. // Dynamic matching failed.
  27. // Skip this interceptor and invoke the next in the chain.
  28. // 动态匹配失败, 跳过此拦截器, 调用拦截器链中的下一个拦截器
  29. return proceed();
  30. }
  31. }
  32. else {
  33. // It's an interceptor, so we just invoke it: The pointcut will have
  34. // been evaluated statically before this object was constructed.
  35. //它是一个拦截器,因此我们只需要调用它:切入点将在构造此对象之前进行静态评估。
  36. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  37. }
  38. }

在这里interceptorsAndDynamicMethodMatchers存放的就是所有匹配到的advisor. 按照顺序,取出advisor. 然后将其转换为MethodInterceptor以后, 调用他的invoke(this)方法,同时将传递当前对象, 在invoke(this)中在此调用proceed()方法. 循环调用. 从interceptorsAndDynamicMethodMatchers取advisor, 直到取出最后一个advisor. 再次调用proceed()则指定调用目标方法.

interceptorsAndDynamicMethodMatchers里面一共有6个advisor

具体调用如下图:

以上就是调用aop的整个过程. 内容还是很多的,需要时间消化.

5.2 spring5源码--spring AOP源码分析三---切面源码分析的更多相关文章

  1. 5.2 Spring5源码--Spring AOP源码分析二

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  2. 5.2 spring5源码--spring AOP源码分析二--切面的配置方式

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  3. 5.1 Spring5源码--Spring AOP源码分析一

    目标: 1.什么是AOP, 什么是AspectJ, 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP 1.1 什么是 ...

  4. spring AOP源码分析(三)

    在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...

  5. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  6. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  7. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  8. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  9. Spring AOP 源码分析系列文章导读

    1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...

随机推荐

  1. 【EXP】WINDOWS下如何导出

    有些时候需要在windows下通过远程来导出数据 那么windows下怎么导出呢 例子: exp hr/hr@192.168.1.222:1521/zhang file=d:backup.dmp lo ...

  2. 聊聊 React

    都说 React 开发效率高,但效率高在哪呢?来细看看. 用 d3 写一个 List: const renderList = data => { d3.select("ul" ...

  3. 使用bapi创建PO遇到问题(BAPI_PO_CREATE1

    今天用 BAPI_PO_CREATE1创建po. 注意事项: vendor 供应商号:长度必须和系统一致,10位.如 2000025要写成 0002000025传递给参数. POITEM 中的 PO_ ...

  4. consul是什么?

    consul概念: consul是用来做注册中心的 他和eureka是一样的 注册中心一般都是集群的形式存在保证高可用 consul像是一个nosql 存储着键值对 可以做存储consul是c/s架构 ...

  5. ElasticSearch Python 基本操作

    创建索引 from elasticsearch import Elasticsearch es = Elasticsearch('192.168.149.96:9200') mappings = { ...

  6. drf认证、节流、权限、版本

    Django rest framework 认证: 作用:验证用户是否登录 在视图类中写上authentication_classes = [ ],这是一个列表 需要实现 authenticate() ...

  7. MongoDB数据库的基本使用!

    MongoDB数据库的基本使用! 1 进入mongoose数据库 在控制台中输入 mongo; 2 查看所有的数据库 show dbs; 3 查看当前数据库的名称 db; 4 查看数据库中的所有的表 ...

  8. NIO非阻塞网络编程原理

    NIO非阻塞网络编程原理 1.NIO基本介绍 Java NIO 全称 java non-blocking IO,是指 JDK 提供的新 API.从 JDK1.4 开始,Java 提供了一系列改进的 输 ...

  9. ETL调优的一些分享(下)(转载)

    如在上篇文章<ETL调优的一些分享(上)>中已介绍的,ETL是构建数据仓库的必经一环,它的执行性能对于数据仓库构建性能有重要意义,因此对它进行有效的调优将十分重要.ETL业务的调优可以从若 ...

  10. python模块----os模块 (操作系统接口模块)

    os模块提供一种使用与操作系统相关的功能的便捷式途径. 一定要使用 import os 而不是 from os import * .这将避免内建的 open() 函数被 os.open() 隐式替换掉 ...