SpringBoot-AOP源碼梳理

1. @EnableAspectJAutoProxy 註解做了什麼?

在springboot中,@EnableAspectJAutoProxy 註解開啓AOP , 在這個註解裏面,通過@Import 給容器中導入AspectJAutoProxyRegistrar 對象.

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {...}

AspectJAutoProxyRegistrar 實現了ImportBeanDefinitionRegistrar接口,通過這個接口可以向容器中增加Bean的定義。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
}

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 這一句往裏走,最後創建了一個AnnotationAwareAspectJAutoProxyCreator 對象的Bean定義,加到註冊器中,key爲org.springframework.aop.config.internalAutoProxyCreator.

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, 	@Nullable Object source) {
  return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
  Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
    ...
  } else {
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    beanDefinition.getPropertyValues().add("order", -2147483648);
    beanDefinition.setRole(2);
    registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
    return beanDefinition;
  }
}

2. 什麼時候註冊1中的AnnotationAwareAspectJAutoProxyCreator對象的定義?

在AspectJAutoProxyRegistrar.registerBeanDefinitions() 方法打斷點調試,查看調用鏈路
在這裏插入圖片描述
大致流程是

spring容器啓動階段的 AbstractApplicationContext.refresh()

invokeBeanFactoryPostProcessors(beanFactory) // 調用工廠的後置處理器, 增加即將加入容器中Bean的定義

this**.**reader.loadBeanDefinitions(configClasses); // 加載所有配置類, 有@Configration註解的類

loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); // 把配置類中import引入的註冊器類加載進來

AspectJAutoProxyRegistrar.registerBeanDefinitions() // 進入到aop的註冊bean定義的方法。

3. 什麼時候創建1中的AnnotationAwareAspectJAutoProxyCreator對象?

在這裏插入圖片描述
通過AnnotationAwareAspectJAutoProxyCreator 類的繼承關係,可以看到它實現了BeanPostProcessor. 在spring容器的啓動過程中 AbstractApplicationContext.refresh() 有專門負責加載所有實現BeanPostProcessor接口的方法

registerBeanPostProcessors(beanFactory); // 加載所有實現BeanPostProcessor接口的方法
它裏面的內容包括如下:

// 獲取所有實現了BeanPostProcessor接口的bean的名稱
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); 
...
  // 逐個創建Bean
  for (String ppName : postProcessorNames) {
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
      // BeanFatory.getBean方法獲取到的就是已經創建好的Bean了
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      priorityOrderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
        internalPostProcessors.add(pp);
      }
    }
    else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
      orderedPostProcessorNames.add(ppName);
    }
    else {
      nonOrderedPostProcessorNames.add(ppName);
    }
  }
...
  // 把創建好的bean加到容器中
  registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

4. 加到容器中的AnnotationAwareAspectJAutoProxyCreator 怎麼生效呢?

AOP的本質是代理,那麼就會有創建Bean的時候,不會使用原本類型指定的對象,而是創建一個增強的對象。那麼我們就從創建bean的過程中尋找。我們知道spring 容器啓動的過程中,會先加載 BeanPostProcessor 等類型的bean,像我們代碼中自己定義的切面等其他業務相關bean,都是之後加載的,從spring容器啓動過程的refresh()方法的代碼順序也可以看出來,這一點在這裏也不重要,我只是提一下。

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
...
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

既然創建的對象是代理對象,那麼直接在AbstractAutowireCapableBeanFactory 類的createBean 方法裏面打斷點,並且給斷電加上Condition, 只在創建我們定義的需要被切的對象的時候斷住,比如我寫了一個Say這個類,那麼我加的條件就是beanName.equals(“say”). 一步步的調試,發現走到applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName) -> wrapIfNecessary(bean, beanName, cacheKey) 方法中的時候,有這麼一段代碼

// Create proxy if we have advice. 
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
  this.advisedBeans.put(cacheKey, Boolean.TRUE);
  Object proxy = createProxy(
    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  this.proxyTypes.put(cacheKey, proxy.getClass());
  return proxy;
}

這個方法是在 AbstractAutoProxyCreator 的 註釋也說的很清楚了,如果有通知就創建代理。通過切點表達式和類的關係,就能找到我們定義的通知方法,被封裝爲Advisor對象。代理創建完成後,可以看到通知方法作爲攔截器鏈添加到了道理對象中。其中的攔截器鏈已經根據Before, After等註解信息排好了順序,排序是使用 ReflectiveAspectJAdvisorFactory 類的METHOD_COMPARATOR 方法實現了,裏面已經定義好了各個註解的順序。
在這裏插入圖片描述
至此,需要增強的對象創建完成,調用的時候,進入CglibAopProxy 的 intercept 方法,因爲我這裏是對類進行的增強,所以spring自動的選則了使用cglib 代理。

先獲取所有的增強方法組成的攔截器鏈

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

把代理對象(Cglib增強後的對象),目標對象(Say),方法,參數,連接器鏈等信息封裝爲一個CglibMethodInvocation 對象,並執行該對象的.proceed() 方法。

public Object proceed() throws Throwable {
  //	We start with an index of -1 and increment early.
  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
  }

  Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    // Evaluate dynamic method matcher here: static part will already have
    // been evaluated and found to match.
    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.
      return proceed();
    }
  }
  else {
    // It's an interceptor, so we just invoke it: The pointcut will have
    // been evaluated statically before this object was constructed.
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  }
}

調試可以看到鏈式的調用,逐個攔截器不斷的調用 mi.proceed(); 逐漸深入到最後一個攔截器MethodBeforeAdviceInterceptor 的時候,可以看到執行了前置通知的方法

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
   return mi.proceed();
}

前置通知執行完以後,mo.proceed()方法中滿足了執行方法本體的條件,被增強的方法本體執行。

//  We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
   return invokeJoinpoint();
}

執行完後線程棧退回到上一層的攔截器,是AspectJAfterAdvice, 因爲是在finally 塊中的,所以必然執行。

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

結束後線程退回到AfterReturningAdviceInterceptor 攔截器,到這裏爲止所有的攔截器中都沒有捕獲異常,所以如果前面有異常的時候,後置攔截器的內容就不執行了。

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

之後回到AspectJAfterThrowingAdvice 攔截器,這裏是在catch 塊中,沒有異常就不執行。

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}

5. 看的時候一定要寫個demo,一遍調試一遍看,光讀文字看不懂的。我的demo如下

/**
 * Author:   susq
 * Date:     2019-08-04 12:06
 */
public class Say {

    public void sayHello() {
        log.info("Say -- sayHello : hello !");
    }
}
@Aspect
public class SayAspect {

    @Pointcut("execution(public * com.su.demo.aop.Say.sayHello(..))")
    public void sayPointCut() {}

    @After("sayPointCut()")
    public void afterSay() {
        System.out.println("=====afterSay=====");
    }

    @AfterThrowing("sayPointCut()")
    public void afterThrow() {
        System.out.println("=====afterThrow=====");
    }

    @Before("sayPointCut()")
    public void beforeSay() {
        System.out.println("=====beforeSay=====");
    }

    @AfterReturning("sayPointCut()")
    public void afterReturn() {
        System.out.println("=====afterReturn=====");
    }

}
@EnableAspectJAutoProxy
@Configuration
public class SayConfig {

    @Bean
    public Say say() {
        return new Say();
    }

    @Bean
    public SayAspect sayAspect() {
        return new SayAspect();
    }
}
public class AppTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(SayConfig.class);
        Say say = configApplicationContext.getBean(Say.class);
        say.sayHello();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章