Spring AOP 源码学习笔记


2022-11-16 0 Spring 源码系列

刘慈欣 -《三体》

弱小和无知不是生存的障碍,傲慢才是。

# 01 - Spring ProxyFactory

ProxyFactory 是 Spring 实现的一个代理工厂类,它也是 Spring AOP 和 Spring 事务实现的底层技术支撑。平时我们在业务代码中也可以使用它,因为用它来创建动态代理对象真实太方便了!!!只需简单的三步:

  1. 创建 ProxyFactory 对象
  2. 设置被代理的 Target
  3. 获取代理对象

最关键的是,ProxyFactory 会自动判断你要使用 JDK 还是 CGLIB 来创建代理对象:






















 


 



public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   // 如果ProxyFactory的isOptimize为true,Spring认为 cglib比jdk动态代理要快
   // 或者isProxyTargetClass为true,
   // 或者被代理对象没有实现接口,
   // 或者只实现了SpringProxy这个接口
   // 那么则利用Cglib进行动态代理,但如果被代理类是接口,或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理

   // 其他情况都会进行JDK动态代理,比如被代理类实现了除SpringProxy接口之外的其他接口

   // 是不是在GraalVM虚拟机上运行
   if (!NativeDetector.inNativeImage() &&
         (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.");
      }
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

下面来看一个 ProxyFactory 的使用 Demo:

// 创建被代理对象
OrderService orderService = new OrderService();
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 设置被代理对象
proxyFactory.setTarget(orderService);
// 添加一个 Advice, 实现切面方法
proxyFactory.addAdvice(new MethodInterceptor() {
   @Nullable
   @Override
   public Object invoke(@NotNull MethodInvocation invocation) throws Throwable
   {
      System.out.println("Around 前");
      Object proceed = invocation.proceed();
      System.out.println("Around 后");
      return proceed;
   }
});
// 获取代理对象
OrderService proxy = (OrderService)proxyFactory.getProxy();
// 代理对象执行方法
proxy.test();

有木有觉得如丝般顺滑 O(∩_∩)O 哈哈~

# 02- AOP 的启动流程

  1. 通过 @EnableAspectJAutoProxy 注解引入 AspectJAutoProxyRegistrar 类, 从而注册一个 AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor
  2. 具体 AOP 的入口在 AnnotationWareAspectJAutoProxyCreator 的父类 AbstractAutoProxyCreatorpostProcessAfterInitialization() 方法:




     





    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    	if (bean != null) {
    		Object cacheKey = getCacheKey(bean.getClass(), beanName);
    		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    			return wrapIfNecessary(bean, beanName, cacheKey); // 包装成 AOP 代理对象
    		}
    	}
    	return bean;
    }
    
  3. 判断当前 bean 是否需要进行 AOP(是否存在匹配的 Advice),如果不需要则直接返回原对象,否则生成一个代理对象返回。

# 03 - 匹配 Advice 的具体逻辑

如何判断当前 Bean 是否存在匹配的 Advice 呢?具体实现过程如下:

  1. 先找到当前 Bean 容器中所有的 Advisor 类型的 Bean 对象,得到 advisors 列表

  2. 再从所有的切面中解析得到 Advisor(最终会封装成 InstantiationModelAwarePointcutAdvisorImpl 对象),将其加入 advisors 了列表中。




     




     



















     



    protected List<Advisor> findCandidateAdvisors() {
    	// Add all the Spring advisors found according to superclass rules.
    	// 先找到所有Advisor类型的Bean对象
    	List<Advisor> advisors = super.findCandidateAdvisors();
    
    	// Build Advisors for all AspectJ aspects in the bean factory.
    	// 再从所有切面中解析得到Advisor对象
    	if (this.aspectJAdvisorsBuilder != null) {
    		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    	}
    	return advisors;
    }
    
    // 具体封装 Advisor 逻辑在 ReflectiveAspectJAdvisorFactory::getAdvisor() 方法
    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
    		int declarationOrderInAspect, String aspectName) {
    
    	validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    
    	// 拿到当前方法所对应的Pointcut对象,但是注意:如果当前方法上是这么写的@After("pointcut()"),那么此时得到的Pointcut并没有去解析pointcut()得到对应的表达式
    	AspectJExpressionPointcut expressionPointcut = getPointcut(
    			candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    	if (expressionPointcut == null) {
    		return null;
    	}
    
    	// expressionPointcut是pointcut
    	// candidateAdviceMethod承载了advice
    	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
    			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }
    
  3. 根据当前 beanClass 类型对所有候选的 Advisor 进行筛选,筛选之后对 Advisor 进行排序。



     

     





     




    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    	// 找到所有的Advisor
    	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    	// 进行筛选
    	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    
    	extendAdvisors(eligibleAdvisors);
    
    	// 对Advisor进行排序,按Ordered接口、@Order注解进行排序
    	if (!eligibleAdvisors.isEmpty()) {
    		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    	}
    	return eligibleAdvisors;
    }
    

# 04 - 切面的筛选逻辑

具体实现在 AopUtils::canApply() 方法中

  1. 先判断类,如果类型不匹配则直接返回 false
    if (!pc.getClassFilter().matches(targetClass)) {
    	return false;
    }
    
  2. 判断方法匹配器 MethodMatcher, 遍历所有的方法,如果有一个方法匹配就返回 true
    for (Method method : methods) {
    	if (introductionAwareMethodMatcher != null ?
    			introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
    			// 判断方法是否匹配
    			methodMatcher.matches(method, targetClass)) {
    		return true;
    	}
    }
    

# 05 - 创建代理对象的过程

  1. 创建一个 ProxyFactory 对象
  2. 添加 Advisors(proxyFactory.addAdvisors(advisors)), 这里需要把匹配到的 Advice 包装成 Advisor 对象:
    • 如果本身就是 Advisor 对象,则直接强制转成 Advisor 对象并返回
    • 如果是 MethodInterceptor 对象,则包装成 DefaultPointcutAdvisor 对象。
    • 如果实现了具体的 AdvisorAdapter 接口(AfterReturningAdviceAdapter/MethodBeforeAdviceAdapter/ThrowsAdviceAdapter),将其包装成 DefaultPointcutAdvisor 对象
  3. 设置被代理对象(proxyFactory.setTargetSource(targetSource));

# 06 - 代理对象的执行过程(核心)

  1. 使用 ProxyFactory 创建代理对象之前,先要往 ProxyFactory 中添加 Advisor 。
  2. 代理对象在执行某个方法时,先判断一下如果是 hashCode() 或者 equals() 方法则不走代理,直接调用被代理对象的方法。
  3. 如果当前执行的方法需要走代理,则会先把 ProxyFactory 中所有的 Advisor 拿出来个当前的执行的方法进行匹配。
  4. 如果匹配的结果为空,则直接调用 target 对应的方法,将匹配成功的 Advisor 都适配成 MethodInterceptor 对象(AfterReturningAdviceAdapter/MethodBeforeAdviceAdapter/ThrowsAdviceAdapter),并按照顺序放入一个列表中,形成一个调用链(chain)。
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
  5. 将代理对象(proxy),被代理对象(target), 当前调用方法(method),代理类和调用链(chain) 封装成一个 MethodInvocation 对象。
    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    // Proceed to the joinpoint through the interceptor chain.
    retVal = invocation.proceed();
    
  6. 调用 invocation.proceed() 方法,开始执行各个 MethodInterceptor 以及被代理对象的对应方法,具体执行逻辑在 ReflectiveMethodInvocation::proceed() 方法中。
  7. 通过递归的方式,一层一层调用对应 Advisor 中的 MethodInterceptor 中的 Invoke() 方法,需要留意的是,这里会对 Advisor 再进行一次筛选:
    InterceptorAndDynamicMethodMatcher dm =
    		(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
    // 动态匹配,根据方法参数匹配
    if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
    	return dm.interceptor.invoke(this);
    }
    else {
    	// Dynamic matching failed.
    	// Skip this interceptor and invoke the next in the chain.
    	// 不匹配则执行下一个MethodInterceptor
    	return proceed();
    }
    
  8. 直到执行完最后一个 MethodInterceptor 了,就会调用 invokeJoinpoint() 方法,从而执行被代理对象的当前方法
    // 当调用完了最后一个interceptor后就会执行被代理方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    	return invokeJoinpoint();
    }