关于spring:Spring源码分析之AOP从解析到调用

4次阅读

共计 24502 个字符,预计需要花费 62 分钟才能阅读完成。

注释:

在上一篇,咱们对 IOC 外围局部流程曾经剖析结束,置信小伙伴们有所播种,从这一篇开始,咱们将会踏上新的旅程,即 Spring 的另一外围:AOP!

首先,为了让大家能更无效的了解 AOP,先带大家过一下 AOP 中的术语:

  • 切面(Aspect):指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级 Java 利用中无关横切关注点的例子。在 Spring AOP 中,切面能够应用在一般类中以@Aspect 注解来实现。
  • 连接点(Join point):在 Spring AOP 中,一个连接点总是代表一个办法的执行,其实就代表加强的办法。
  • 告诉(Advice):在切面的某个特定的连接点上执行的动作。告诉有多种类型,包含 aroundbeforeafter等等。许多 AOP 框架,包含 Spring 在内,都是以拦截器做告诉模型的,并保护着一个以连接点为核心的拦截器链。
  • 指标对象(Target):指标对象指将要被加强的对象。即蕴含主业务逻辑的类的对象。
  • 切点(Pointcut):匹配连接点的断言。告诉和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的办法时)。切点表达式如何和连接点匹配是 AOP 的外围:Spring 默认应用 AspectJ 切点语义。
  • 参谋(Advisor):参谋是 Advice 的一种包装体现,Advisor 是 Pointcut 以及 Advice 的一个联合,用来治理 Advice 和 Pointcut。
  • 织入(Weaving):将告诉切入连接点的过程叫织入
  • 引入(Introductions):能够将其余接口和实现动静引入到 targetClass 中

一个栗子

术语看完了,咱们先上个 Demo 回顾一下吧~

  1. 首先,应用 EnableAspectJAutoProxy 注解开启咱们的 AOP

    @ComponentScan(basePackages = {"com.my.spring.test.aop"})
    @Configuration
    @EnableAspectJAutoProxy
    public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
            IService service = context.getBean("service", IService.class);
            service.doService();}
    }
  2. 写一个接口

    public interface IService {void doService();
    }
  3. 写一个实现类

    @Service("service")
    public class ServiceImpl implements IService{
    
        @Override
        public void doService() {System.out.println("do service ...");
        }
    }
  4. 写一个切面

    @Aspect
    @Component
    public class ServiceAspect {@Pointcut(value = "execution(* com.my.spring.test.aop.*.*(..))")
        public void pointCut() {}
    
        @Before(value = "pointCut()")
        public void methodBefore(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();
            System.out.println("执行指标办法【" + methodName + "】的【前置告诉】,入参:" + Arrays.toString(joinPoint.getArgs()));
        }
    
        @After(value = "pointCut()")
        public void methodAfter(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();
            System.out.println("执行指标办法【" + methodName + "】的【后置告诉】,入参:" + Arrays.toString(joinPoint.getArgs()));
        }
    
        @AfterReturning(value = "pointCut()")
        public void methodReturn(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();
            System.out.println("执行指标办法【" + methodName + "】的【返回告诉】,入参:" + Arrays.toString(joinPoint.getArgs()));
        }
    
        @AfterThrowing(value = "pointCut()")
        public void methodThrow(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();
            System.out.println("执行指标办法【" + methodName + "】的【异样告诉】,入参:" + Arrays.toString(joinPoint.getArgs()));
        }
    }
  5. 测试运行

    执行指标办法【doService】的【前置告诉】,入参:[]
    do service ...
    执行指标办法【doService】的【返回告诉】,入参:[]
    执行指标办法【doService】的【后置告诉】,入参:[]

以上

Demo 看完了,运行成果也进去了,AOP 已失效,但如何失效的呢?相比于咱们一般应用 Bean 的 Demo,在这里,咱们只不过加上了一个 @EnableAspectJAutoProxy 注解以及一个标识了 @Aspectj 的类,那么咱们先看看 @EnableAspectJAutoProxy 这个注解做了什么吧~

开启 AOP

以下是笔者所画的大抵流程图

​ 其中 AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar,所以在解决BeanFactoryPostProcessor 逻辑时将会调用 registerBeanDefinitions 办法,此时就会把 AnnotationAwareAspectJAutoProxyCreator 注册到容器中,其中 BeanFactoryPostProcessor 的逻辑就不再说了,往期文章有过详细分析。而 AnnotationAwareAspectJAutoProxyCreator 的类图如下:

咱们发现 AnnotationAwareAspectJAutoProxyCreator 是实现了 BeanPostProcessor 接口的类,所以它其实是一个后置处理器,那么,还记得在创立 Bean 过程中的 BeanPostProcessor 九次调用机会吗?不记得也没关系,AnnotationAwareAspectJAutoProxyCreator起作用的中央是在 bean 的实例化前以及初始化后,别离对应着解析切面和创立动静代理的过程,当初,就让咱们先来看看解析切面的过程吧~

解析切面

解析切面的流程如下图所示:

咱们曾经理解到切面解析的过程是由 AnnotationAwareAspectJAutoProxyCreator 实现的,而 AnnotationAwareAspectJAutoProxyCreator 又继承了AbstractAutoProxyCreator,所以首先,咱们先会来到AbstractAutoProxyCreator#postProcessBeforeInstantiation

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {// class 类型是否为(Advice, Pointcut, Advisor, AopInfrastructureBean)
  // shouldSkip 中将会解析切面
  if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return null;
  }
}

调用到子类的AspectJAwareAdvisorAutoProxyCreator#shouldSkip

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
  // 寻找 advisor
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  for (Advisor advisor : candidateAdvisors) {
    if (advisor instanceof AspectJPointcutAdvisor &&
        ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}
  }
  return super.shouldSkip(beanClass, beanName);
}

findCandidateAdvisors

protected List<Advisor> findCandidateAdvisors() {
  // 寻找实现了 Advisor 接口的类, 因为咱们个别不会以接口的形式实现切面,这里返回 null
  List<Advisor> advisors = super.findCandidateAdvisors();
  if (this.aspectJAdvisorsBuilder != null) {
    // 这里将解析出所有的切面
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  return advisors;
}

buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() {
  // aspectBeanNames 有值则阐明切面已解析结束
  List<String> aspectNames = this.aspectBeanNames;
  // Double Check
  if (aspectNames == null) {synchronized (this) {
      aspectNames = this.aspectBeanNames;
      if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();
        aspectNames = new ArrayList<>();
        // 取出是 Object 子类的 bean,其实就是所有的 bean
        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
        for (String beanName : beanNames) {
          // 取得该 bean 的 class
          Class<?> beanType = this.beanFactory.getType(beanName);
          // 判断是否有标识 @AspectJ 注解
          if (this.advisorFactory.isAspect(beanType)) {
            // 将 beanName 放入汇合中
            aspectNames.add(beanName);
            // 将 beanType 和 beanName 封装到 AspectMetadata 中
            AspectMetadata amd = new AspectMetadata(beanType, beanName);
            // Kind 默认为 SINGLETON
            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
              MetadataAwareAspectInstanceFactory factory =
                new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
              // 这里会通过 @Before @After 等标识的办法获取到所有的 advisor
              List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
              if (this.beanFactory.isSingleton(beanName)) {
                // 将获取到的所有 advisor 放入缓存
                this.advisorsCache.put(beanName, classAdvisors);
              }
              advisors.addAll(classAdvisors);
            }
          }
        }
        // 将所有解析过的 beanName 赋值
        this.aspectBeanNames = aspectNames;
        return advisors;
      }
    }
  }
  // aspectNames 不为空,象征有 advisor,取出之前解析好的所有 advisor
  List<Advisor> advisors = new ArrayList<>();
  // 获取到所有解析好的 advisor
  for (String aspectName : aspectNames) {List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
    if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);
    }
        return advisors;
    }

advisorFactory.getAdvisors

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 获取到标识了 @AspectJ 的 class,其实就是刚刚封装的 class
  Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  // 获取 className
  String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
  
  List<Advisor> advisors = new ArrayList<>();
  
  // 拿出该类除了标识 @PointCut 的所有办法进行遍历 getAdvisorMethods 时会对 method 进行一次排序
  // 排序程序 Around, Before, After, AfterReturning, AfterThrowing
  for (Method method : getAdvisorMethods(aspectClass)) {
    // 获取到 advisor
    Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
    if (advisor != null) {
      // 退出到汇合中
      advisors.add(advisor);
    }
  }
}

咱们先看下 getAdvisorMethods 办法

private List<Method> getAdvisorMethods(Class<?> aspectClass) {final List<Method> methods = new ArrayList<>();
  // 循环遍历该类和父类的所有办法
  ReflectionUtils.doWithMethods(aspectClass, method -> {
    // 排除 @PointCut 标识的办法
    if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {methods.add(method);
    }
  }, ReflectionUtils.USER_DECLARED_METHODS);
  if (methods.size() > 1) {
    // 以 Around, Before, After, AfterReturning, AfterThrowing 的程序自定义排序
    methods.sort(METHOD_COMPARATOR);
  }
  return methods;
}

不晓得小伙伴们对 ReflectionUtils.doWithMethods 这个工具类熟不相熟呢,这个工具类在之前剖析 Bean 创立过程时可是呈现了好屡次呢,并且咱们也是能够应用的

当初,曾经获取到切面中的所有办法了,那么接下来就该对这些办法解析并进行封装成 advisor 了~

getAdvisor

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {
    // 获取办法上的切点表达式
  AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
  // 封装成对象返回,创建对象时将会解析办法创立 advice
  return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                                                        this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

获取切点表达式的过程其实非常简单,即是解析办法上的注解,取出注解上的 value 即可

getPointcut

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  // 查找办法上和 AspectJ 相干注解
  AspectJAnnotation<?> aspectJAnnotation =
    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  // 设置切点表达式
  AspectJExpressionPointcut ajexp =
    new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  // PointcutExpression 为注解上 value 属性的值
  ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  if (this.beanFactory != null) {ajexp.setBeanFactory(this.beanFactory);
  }
  return ajexp;
}

new InstantiationModelAwarePointcutAdvisorImpl,在这里,才会真正创立出 advice

public InstantiationModelAwarePointcutAdvisorImpl(){
  //... 省略赋值过程...
  // 实例化出 advice
  this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
  // 获取 advice,aspectJAdviceMethod 为办法,aspectName 为切面类
  Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
                                                       this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
  return (advice != null ? advice : EMPTY_ADVICE);
}
public Advice getAdvice(){
  // 依据办法获取到注解信息
  AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  AbstractAspectJAdvice springAdvice;
  // 依据注解类型返回对象,创建对象的过程都是一样的,都是调用父类的构造方法
  // candidateAdviceMethod 为切面的办法,expressionPointcut 是切点
  switch (aspectJAnnotation.getAnnotationType()) {
    case AtPointcut
      return null;
    case AtAround:
      springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtBefore:
      springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtAfter:
      springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
      //... 省略其余的 advice
    default:
      throw new UnsupportedOperationException("Unsupported advice type on method:" + candidateAdviceMethod);
  }
  return springAdvice;
}

springAdvice 已创立结束,意味着切面中的某个办法曾经解析结束了,其余的办法解析过程大抵也是类似的

小结

其实解析切面自身并不简单,只是 Spring 中将切面类封装来封装去容易使人凌乱,如 buildAspectJAdvisors 办法中,封装了一个 AspectMetadata amd = new AspectMetadata(beanType, beanName);,又立刻发动断定amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON,其实这里齐全能够变为AjTypeSystem.getAjType(currClass).getPerClause().getKind() == PerClauseKind.SINGLETONAjTypeSystem.getAjType(currClass)new AspectMetadata的一部分逻辑,笔者这里给大家总结一下吧。

首先,循环所有的 beanName,找到带有 @Aspectj 注解的 class, 获取到 class 中的所有办法进行遍历解析,取出办法注解上的值(切点:pointcut),而后把办法,切点表达式,封装了 BeanFactory,BeanName 的 factory 封装成相应的 SpringAdvice, 由 SpringAdvice 和 pointcut 组合成一个 advisor。

创立代理对象

切面曾经解析结束,接下来,咱们就来看看如何把解析出的切面织入到指标办法中吧

但,在这之前,还有必要给小伙伴们补充一点前置常识。

咱们晓得,一个 bean 是否可能被 aop 代理,取决于它是否满足代理条件,即为是否可能被切点表达式所命中,而在 Spring AOP 中,bean 与切点表达式进行匹配的是 AspectJ 实现的,并非 Spring 所实现的,所以咱们先来看看 AspectJ 如何匹配出适合的 bean 的吧

栗子

首先须要引入 org.aspectj:aspectjweaver 依赖

一个 Service,包名为com.my.spring.test.aop

package com.my.spring.test.aop;

/**
 * 切点表达式能够匹配的类
 *
 */
public class ServiceImpl{
    /**
     * 切点表达式能够匹配的办法
     */
  public void doService() {System.out.println("do service ...");
  }
    public void matchMethod() {System.out.println("ServiceImpl.notMatchMethod");
    }
}

而后,咱们本人封装一个用于匹配的工具类,具体性能大家看正文哈哈

package com.my.spring.test.aspectj;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;

import java.lang.reflect.Method;

/**
 * aop 工具
 */
public class AOPUtils {
    // AspectJ 的固定写法,获取一个切点解析器
    static PointcutParser parser = PointcutParser
            .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(PointcutParser.getAllSupportedPointcutPrimitives(), ClassLoader.getSystemClassLoader());
    // 切点表达式
    private static PointcutExpression pointcutExpression;

    /**
     * 初始化工具类,咱们须要先获取一个切点表达式
     *
     * @param expression 表达式
     */
    public static void init(String expression){
        // 解析出一个切点表达式
        pointcutExpression =  parser.parsePointcutExpression(expression);
    }

    /**
     * 第一次筛选,依据类筛选,也叫做粗筛
     *
     * @param targetClass 指标类
     * @return 是否匹配
     */
    public static boolean firstMatch(Class<?> targetClass){
    // 依据类筛选
        return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    }

    /**
     * 第二次筛选,依据办法筛选,也叫做精筛,精筛通过则阐明齐全匹配
     * ps: 也能够应用该办法进行精筛,粗筛的目标是进步性能,第一次间接过滤掉不适合的类再缓缓精筛
     * 
     * @param method 办法
     * @return 是否匹配
     */
    public static boolean lastMatch(Method method){
    // 依据办法筛选
        ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
        return shadowMatch.alwaysMatches();}

}

测试

public class AOPUtilsTest {public static void main(String[] args) throws NoSuchMethodException {
        // 定义表达式
        String expression = "execution(* com.my.spring.test.aop.*.*(..))";
        // 初始化工具类
        AOPUtils.init(expression);
        // 粗筛
        boolean firstMatch = AOPUtils.firstMatch(ServiceImpl.class);
        if(firstMatch){System.out.println("第一次筛选通过");
            // 失常状况应该是获取所有办法进行遍历,我这里偷懒了~
            Method doService = ServiceImpl.class.getDeclaredMethod("doService");
            // 精筛
            boolean lastMatch = AOPUtils.lastMatch(doService);
            if(lastMatch){System.out.println("第二次筛选通过");
            }
            else{System.out.println("第二次筛选未通过");
            }
        }
        else {System.out.println("第一次筛选未通过");
        }
    }
}

后果(就不截图了,狐疑的小伙伴能够本人试试~)

第一次筛选通过
第二次筛选通过

当咱们新建一个类Test, 把切点表达式换成

execution(* com.my.spring.test.aop.Test.*(..))

测试后果为

第一次筛选未通过

再把切点表达式换成指定的办法

execution(* com.my.spring.test.aop.*.matchMethod(..))

后果

第一次筛选通过
第二次筛选未通过

到这里,小伙伴们应该明确了 AspectJ 的应用办法吧

代理对象创立过程

接下来,咱们就来看看 Spring 是如何应用 AspectJ 匹配出相应的 advisor 并创立代理对象的吧,以下为创立代理对象的大抵途程图

创立代理对象是在 bean 初始化后实现的,所以对应的 beanPostProcessor 调用机会为postProcessAfterInitialization

AbstractAutoProxyCreator#postProcessAfterInitialization

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {
            // 获取缓存 key 值,其实就是 beanName
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 判断缓存中是否有该对象,有则阐明该对象已被动静代理,跳过
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 依据 bean 获取到匹配的 advisor
  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  if (specificInterceptors != DO_NOT_PROXY) {
    // 创立代理对象
    Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    return proxy;
  }
  return bean;
}

getAdvicesAndAdvisorsForBean

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
  // 获取适合的 advisor
  List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  return advisors.toArray();}

findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  // 先获取到所有的 advisor, 这里和解析过程雷同,因为曾经解析好,所以会间接从缓存中取出
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  // 筛选出匹配的 advisor
  List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  // 减少一个默认的 advisor
  extendAdvisors(eligibleAdvisors);
  if (!eligibleAdvisors.isEmpty()) {
    // 排序
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  }
  return eligibleAdvisors;
}

findAdvisorsThatCanApply

protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
  // 查找匹配的 advisor
  return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}

findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz){List<Advisor> eligibleAdvisors = new ArrayList<>();
  for (Advisor candidate : candidateAdvisors) {
    // 判断是否匹配
    if (canApply(candidate, clazz, hasIntroductions)) {
      // 退出到适合的 advisors 汇合中
      eligibleAdvisors.add(candidate);
    }
  }
  return eligibleAdvisors;
}

canApply

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pca = (PointcutAdvisor) advisor;
    // 判断是否匹配
    return canApply(pca.getPointcut(), targetClass, hasIntroductions);
  }
  else {
    // It doesn't have a pointcut so we assume it applies.
    return true;
  }
}

canApply

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    // 第一次筛选,对 class 筛选判断是否满足匹配条件
  // 这里将会初始化切点表达式
  if (!pc.getClassFilter().matches(targetClass)) {return false;}
  
  IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  }
  
  for (Class<?> clazz : classes) {Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    // 循环所有办法进行第二次筛选,判断是否有办法满足匹配条件
    for (Method method : methods) {
      if (introductionAwareMethodMatcher != null ?
          introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
          methodMatcher.matches(method, targetClass)) {return true;}
    }
  }
  return false;
}

pc.getClassFilter()

public ClassFilter getClassFilter() {obtainPointcutExpression();
  return this;
}

obtainPointcutExpression

private PointcutExpression obtainPointcutExpression() {if (this.pointcutExpression == null) {
    // 确认类加载器
    this.pointcutClassLoader = determinePointcutClassLoader();
    // 创立切点表达式
    this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
  }
  return this.pointcutExpression;
}

buildPointcutExpression

private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
  // 初始化切点解析器
  PointcutParser parser = initializePointcutParser(classLoader);
  PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
  for (int i = 0; i < pointcutParameters.length; i++) {pointcutParameters[i] = parser.createPointcutParameter(this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
  }
  // 应用切点解析器进行解析表达式获取切点表达式
  return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
                                        this.pointcutDeclarationScope, pointcutParameters);
}

initializePointcutParser

private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
  // 取得切点解析器
  PointcutParser parser = PointcutParser
    .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader);
  parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler());
  return parser;
}

pc.getClassFilter 便是实现了以上事件,此时再进行调用 matchs 办法

public boolean matches(Class<?> targetClass) {PointcutExpression pointcutExpression = obtainPointcutExpression();
  // 应用切点表达式进行粗筛
  return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}

introductionAwareMethodMatcher.matches 同样如此

以上便是寻找适合的 advisor 的过程,上面,就是通过这些 advisor 进行创立动静代理了

createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
            @Nullable Object[] specificInterceptors, TargetSource targetSource) {ProxyFactory proxyFactory = new ProxyFactory();
  proxyFactory.copyFrom(this);
    // 将 specificInterceptors(当初是 Object)转化为 Advisor 返回
  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  // 赋值到 proxyFactory 的 advisors 属性中
  proxyFactory.addAdvisors(advisors);
  proxyFactory.setTargetSource(targetSource);
  customizeProxyFactory(proxyFactory);
  // 创立动静代理
  return proxyFactory.getProxy(getProxyClassLoader());
}

proxyFactory.getProxy

public Object getProxy(@Nullable ClassLoader classLoader) {
  // 创立代理对象
  return createAopProxy().getProxy(classLoader);
}

createAopProxy

protected final synchronized AopProxy createAopProxy() {
  // 创立 AOP 代理对象
  return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  // @EnableAspectJAutoProxy 的 proxyTargetClass 是否配置为 true
  if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
      throw new AopConfigException("TargetSource cannot determine target class:" +
                                   "Either an interface or a target is required for proxy creation.");
    }
    // 如何是接口则创立 jdk 动静代理
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);
    }
    // cglib 动静代理
    return new ObjenesisCglibAopProxy(config);
  }
  // 默认是 jdk 动静代理
  else {return new JdkDynamicAopProxy(config);
  }
}
public Object getProxy(@Nullable ClassLoader classLoader) {
  // 获取到代理的接口
  Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  // 创立 jdk 代理,传入的为 JdkDynamicAopProxy 对象,外面蕴含了被代理的 bean 以及匹配的 advisor
  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

动静代理创立实现~

代理对象调用过程

对象都给你创立好了,接下当然是开.. 发动调用咯

以下是调用的大抵流程图

代理对象被调用的是 invoke 办法,咱们所创立的代理对象为JdkDynamicAopProxy,所以

JdkDynamicAopProxy#invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  Object oldProxy = null;
  boolean setProxyContext = false;
  // 取出包装了被代理 bean 的对象 -> 创立代理对象时的 SingletonTargetSource, advised 为 ProxyFactory
  TargetSource targetSource = this.advised.targetSource;
  Object target = null;
  // 拿到 bean
  target = targetSource.getTarget();
  Class<?> targetClass = (target != null ? target.getClass() : null);
  // 将所有 advisor 中的 advice 取出,并转化为对应的 interceptor
  List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  // 创立一个最外层的 MethodInvocation 用于发动调用
  MethodInvocation invocation =
    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  // 发动链式调用
  Object retVal = invocation.proceed();
  return retVal;
}

咱们先看获取 interceptor 的过程

getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
  // 将所有 advisor 中的 advice 取出并封装成 intercept
  return this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
    // 创立一个 advisor 适配器的注册器用于转化 advice,创立时将默认注册三个适配器
  AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
  Advisor[] advisors = config.getAdvisors();
  // 循环遍历所有 advisor
  for (Advisor advisor : advisors) {
      // 将 advisor 中的 advice 转化为 interceptor
    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    interceptorList.addAll(Arrays.asList(interceptors));
    return interceptorList;
  }
}

GlobalAdvisorAdapterRegistry.getInstance() 类初始化时调用静态方法

private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry()
public static AdvisorAdapterRegistry getInstance() {return instance;}
public DefaultAdvisorAdapterRegistry() {
  // 注册三个适配器
  registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
  registerAdvisorAdapter(new AfterReturningAdviceAdapter());
  registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
  // 将适配器退出汇合
  this.adapters.add(adapter);
}

registry.getInterceptors 这外面蕴含了 advice 转化成 interceptor 的过程

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);
  Advice advice = advisor.getAdvice();
  // advice 自身是否就是 MethodInterceptor
  if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);
  }
  for (AdvisorAdapter adapter : this.adapters) {// 判断 advice 是哪个 advice 如:(advice instanceof MethodBeforeAdvice)
    if (adapter.supportsAdvice(advice)) {
      // 将 advice 封装到对应的 interceptor
      interceptors.add(adapter.getInterceptor(advisor));
    }
  }
  return interceptors.toArray(new MethodInterceptor[0]);
}

若 adapter 为MethodBeforeAdviceAdapter,则

public MethodInterceptor getInterceptor(Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
  return new MethodBeforeAdviceInterceptor(advice);
}

其余 advice 转化过程雷同

以上,便将所有的 advice 转化成了 interceptor,接下来,则是经典的链式递归调用过程

以下过程小伙伴们能够对照流程图浏览,毕竟递归还是有些简单,须要肯定的功底

ReflectiveMethodInvocation#proceed

public Object proceed() throws Throwable {
  // currentInterceptorIndex 初始值为 -1
  // 当 currentInterceptorIndex 等于 advice 的数量减一时,则调用指标办法
  // 因为 advice 已排好序,所以调用程序为 before, after, afterReturn, afterThrowing
  // 留神,并非调用到相应的 advice 就会执行 advice 办法,这里是相似递归调用的形式,会存在一个归过程
  // 有些是递的时候发动调用,如 beforeAdvice, 但有些则是归的时候发动调用,如 afterAdvice
  // 递归的终止条件则是这上面这个 return invokeJoinpoint();
  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();
  }
    // currentInterceptorIndex 自增并获取到 interceptor
  Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  // 将 interceptro 强转为 MethodInterceptor 发动调用
  return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

此时 currentInterceptorIndex 值为 0,而咱们的 advice 为 4 个(去除了默认的),所以当 currentInterceptorIndex 为 3 时便会调用咱们的理论办法

首先调用的是 MethodBeforeAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
  // 调用前置告诉
  this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
  return mi.proceed();}

mi 为传入的 this,所有 mi.proceed()将会回到最开始的办法

再次循环,此时 currentInterceptorIndex 值为 1

调用的是 AspectJAfterAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
  try {return mi.proceed();
  }
  finally {
    // finally 意味着不管怎样都会被调用
    invokeAdviceMethod(getJoinPointMatch(), null, null);
  }
}

持续,此时 currentInterceptorIndex 值为 2

调用的是 AfterReturningAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed();
  this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
  return retVal;
}

持续,此时 currentInterceptorIndex 值为 3

调用的是 AspectJAfterThrowingAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
  try {return mi.proceed();
  }
  catch (Throwable ex) {if (shouldInvokeOnThrowing(ex)) {
      // 调用异样告诉
      invokeAdviceMethod(getJoinPointMatch(), null, ex);
    }
    // 往外抛出异样
    throw ex;
  }
}

所以如果咱们的业务办法产生了异样,会调用到异样告诉,而这里又把异样往外抛,所以 afterReturn 就会被跳过间接到 after 的 finally 办法

当初 currentInterceptorIndex 值为 3 了,再回调最后的办法中时,就会调用到咱们的业务办法了。调用结束则进行归的过程,调用过程便完结了。

以上,便是整个 AOP 的过程了

本篇文章中波及到图片的矢量图地址为:https://www.processon.com/vie…,有须要的小伙伴可自取

下文预报:Spring 源码剖析之事务管理(上)

Spring 源码系列
  1. Spring 源码剖析之 IOC 容器预启动流程(已完结)
  2. Spring 源码剖析之 BeanFactory 体系结构(已完结)
  3. Spring 源码剖析之 BeanFactoryPostProcessor 调用过程(已完结)
  4. Spring 源码剖析之 Bean 的创立过程(已完结)
  5. Spring 源码剖析之什么是循环依赖及解决方案(已完结)
  6. Spring 源码剖析之 AOP 从解析到调用(已完结)
  7. Spring 源码剖析之事务管理(上),事物治理是 spring 作为容器的一个特点,总结一下他的根本实现与原理吧
  8. Spring 源码剖析之事务管理(下),对于他的底层事物隔离与事物流传原理,重点剖析一下
Spring Mvc 源码系列
  1. SpringMvc 体系结构
  2. SpringMvc 源码剖析之 Handler 解析过程
  3. SpringMvc 源码剖析之申请链过程

另外笔者公众号:奇客工夫,有更多精彩的文章,有趣味的同学,能够关注

正文完
 0