• Spring源码分析之AOP从解析到调用


    正文:

    在上一篇,我们对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/view/link/5fa8afdae401fd45d109f257,有需要的小伙伴可自取

    下文预告: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源码分析之请求链过程

    另外笔者公众号:奇客时间,有更多精彩的文章,有兴趣的同学,可以关注

  • 相关阅读:
    线程的故事:我的3位母亲成就了优秀的我!
    Semaphore自白:限流器用我就对了!
    CyclicBarrier:人齐了,老司机就可以发车了!
    最新版Swagger 3升级指南和新功能体验!
    阿里巴巴Druid,轻松实现MySQL数据库连接加密!
    try-catch-finally中的4个大坑,不小心就栽进去了!
    Git 常用命令总结,将会持续更新
    oracle in 条件超长问题解决
    关于java中使用split方法末尾空值被丢弃的问题
    Ubuntu 嵌入式开发准备
  • 原文地址:https://www.cnblogs.com/tomakemyself/p/14131421.html
Copyright © 2020-2023  润新知