天天看點

Spring 源碼(六)Spring AOP源碼解析

AOP 面向切面程式設計,相對于OOP面向對象程式設計。

Spring AOP存在的目的是為了解耦。AOP可以讓一組類共享相同的行為。在OOP中隻能通過繼承類和實作接口,來使代碼的耦合度增強,且類繼承隻能是單繼承,阻礙更多的行為添加到一組類上,AOP彌補了OOP的不足。

Spring支援AspectJ的注解式切面程式設計,基本定義如下:

  1. 使用@AspectJ聲明一個切面。
  2. 使用@After、@Before、@Around定義建言(adivice),可以直接将攔截規則(切點)作為參數。
  3. 其中@After、@Before、@Around參數的攔截規則為切點(PointCut),為了使切點複用,可以使用@PointCut專門定義攔截規則,然後在@After、@Before、@Around的參數中調用。
  4. 其中符合條件的每一個被攔截處為連接配接點(JoinPoint)。

AspectJ提供了五種定義通知的标注:

  • @Before:前置通知,在調用目标方法之前執行通知定義的任務
  • @After:後置通知,在目标方法執行結束後,無論執行結果如何都執行通知定義的任務
  • @AfterReturning:後置通知,在目标方法執行結束後,如果執行成功,則執行通知定義的任務
  • @AfterThrowing:異常通知,如果目标方法執行過程中抛出異常,則執行通知定義的任務
  • @Around:環繞通知,在目标方法執行前和執行後,都需要執行通知定義的任務

示例

定義一個切入點

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log {
    String value() default "";
}      

聲明一個切面

// 切面
@Aspect
public class LogAspect {

    // 切點
    @Pointcut("@annotation(com.xiaolyuh.aop.annotations.Log)")
    public void pointCutMethod() {
    }

    @Pointcut("@within(com.xiaolyuh.aop.annotations.Log)")
    public void pointCutType() {
    }

    // 建言
    @Before("pointCutMethod() || pointCutType()")
//    @Before("execution(* com.xiaolyuh.aop.controller.UserController.*(..))")
    public void before(JoinPoint joinPoint) {
        // 通過反射可以獲得注解上的屬性,然後做日志記錄相關的操作
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        System.out.println("日志切面 befor:" + log.value() + ":::" + JSON.toJSONString(joinPoint.getArgs()));
    }

    @After(value = " pointCutMethod() || pointCutType()")
    public void after(JoinPoint joinPoint) {
        // 通過反射可以獲得注解上的屬性,然後做日志記錄相關的操作  
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        System.out.println("日志切面 after:" + log.value());
    }

    @AfterReturning(value = " pointCutMethod() || pointCutType()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        // 通過反射可以獲得注解上的屬性,然後做日志記錄相關的操作
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        System.out.println("日志切面 afterReturning:" + log.value() + ":::" + JSON.toJSONString(result));
    }

    @AfterThrowing(value = " pointCutMethod() || pointCutType()", throwing = "t")
    public void afterThrowing(JoinPoint joinPoint, Throwable t) {
        // 通過反射可以獲得注解上的屬性,然後做日志記錄相關的操作
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        System.out.println("日志切面 afterThrowing:" + log.value() + ":::" + JSON.toJSONString(t.getStackTrace()));
    }

    @Around(value = " pointCutMethod() || pointCutType()")
    public Object Around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 通過反射可以獲得注解上的屬性,然後做日志記錄相關的操作
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);

        System.out.println("日志切面 Around before:" + log.value() + ":::" + JSON.toJSONString(joinPoint.getArgs()));
        Object result = joinPoint.proceed();
        System.out.println("日志切面 Around after:" + log.value() + ":::" + JSON.toJSONString(result));

        return result;
    }
}      

開啟AOP的支援

@Configuration
@EnableAspectJAutoProxy
@ComponentScan({"com.xiaolyuh.aop"})
public class AopConfig {

    @Bean
    public LogAspect logAspect() {
        return new LogAspect();
    }
}      

業務類的是用方式

@Controller
public class UserController {

    // 連接配接點
    @Log("除法接口")
    public Object div(int i, int j) {
        System.out.println("業務接口執行-------------------");
        return i / j;
    }

    public Object add(int i, int j) {
        return i + j;
    }
}      

測試類

public class AopTest extends BaseTest {

    @Before
    public void before() {
        super.before(AopConfig.class);
    }

    @Test
    public void contextTest() {

        PrintSpringBeanUtil.printlnBean(context);
        System.out.println("開始比較容器中的Bean");
        UserController bean = context.getBean(UserController.class);
        bean.div(4, 2);
    }
}      

執行結果:

日志切面 Around before:除法接口:::[4,2]
日志切面 befor:除法接口:::[4,2]
業務接口執行-------------------
日志切面 Around after:除法接口:::2
日志切面 after:除法接口
日志切面 afterReturning:除法接口:::2      

注冊 AnnotationAwareAspectJAutoProxyCreator 後置處理器

@EnableAspectJAutoProxy

​@EnableAspectJAutoProxy​

​的主要作用是開啟對AOP的支援。源碼如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
  // true:使用CGLIB, false:如果是接口使用JDK,不是接口使用CGLIB 
  boolean proxyTargetClass() default false;
  boolean exposeProxy() default false;
}      

主要起作用的是​

​@Import(AspectJAutoProxyRegistrar.class)​

​​。​

​AspectJAutoProxyRegistrar​

​​注冊器的主要作用是将​

​AnnotationAwareAspectJAutoProxyCreator​

​後置處理器注冊到容器中。

AspectJAutoProxyRegistrar

​AspectJAutoProxyRegistrar​

​​實作了​

​ImportBeanDefinitionRegistrar​

​​接口,實作該接口後Spring 在解析配置類的時候會通過後置處理器ConfigurationClassPostProcessor調用到 ​

​ImportBeanDefinitionRegistrar#registerBeanDefinitions()​

​​方法,并将​

​AnnotationAwareAspectJAutoProxyCreator​

​後置處理器的Bean定義注冊到容器中。

對于 AOP 的實作,基本上都是靠AnnotationAwareAspectJAutoProxyCreator 去完成的,它可以根據 @Point 注解定義的切點來自動代理相比對的 bean。但是為了配置簡便, Spring 使用了自定義配來幫助我們自動注冊 AnnotationAwareAspectJAutoProxyCreator。實作如下:

調用鍊路:

registerOrEscalateApcAsRequired:121, AopConfigUtils (org.springframework.aop.config)
registerAspectJAnnotationAutoProxyCreatorIfNecessary:90, AopConfigUtils (org.springframework.aop.config)
registerAspectJAnnotationAutoProxyCreatorIfNecessary:86, AopConfigUtils (org.springframework.aop.config)
registerBeanDefinitions:45, AspectJAutoProxyRegistrar (org.springframework.context.annotation)
loadBeanDefinitionsFromRegistrars:360, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
loadBeanDefinitionsForConfigurationClass:144, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
loadBeanDefinitions:116, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
processConfigBeanDefinitions:320, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
refresh:525, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)      

源碼:

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
  // 根據需要注冊或更新 AbstractAdvisorAutoProxyCreator
  return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
  Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
    // 如果已經存在了自動代理建立器且存在的自動代理建立器與現在的不一緻,那麼需要根據優先級來判斷到底需要使用那個AbstractAdvisorAutoProxyCreator
    BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
    if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
      int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
      int requiredPriority = findPriorityForClass(cls);
      if (currentPriority < requiredPriority) {
        // 改變bean最總要的是改變bean對應的className屬性
        apcDefinition.setBeanClassName(cls.getName());
      }
    }
    // 如果已經存在的代理建立器與現在的一樣,則不需要再次建立
    return null;
  }
  // 注冊 AbstractAdvisorAutoProxyCreator
  RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
  beanDefinition.setSource(source);
  beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
  beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
  return beanDefinition;
}      

AnnotationAwareAspectJAutoProxyCreator

下面是​

​AnnotationAwareAspectJAutoProxyCreator​

​​的類圖,從類圖我們可以看出​

​AnnotationAwareAspectJAutoProxyCreator​

​​它是一個實作了​

​Ordered​

​​接口的的後置處理器。和其他後置處理器一樣,也會在​

​registerBeanPostProcessors​

​方法中完成後置處理器的執行個體化,并注冊到Spring 容器。

Spring 源碼(六)Spring AOP源碼解析

解析切面類擷取增強器

找到增強器

調用鍊路:

buildAspectJAdvisors:109, BeanFactoryAspectJAdvisorsBuilder (org.springframework.aop.aspectj.annotation)
findCandidateAdvisors:90, AnnotationAwareAspectJAutoProxyCreator (org.springframework.aop.aspectj.annotation)
shouldSkip:103, AspectJAwareAdvisorAutoProxyCreator (org.springframework.aop.aspectj.autoproxy)
postProcessBeforeInstantiation:248, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsBeforeInstantiation:1045, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
resolveBeforeInstantiation:1019, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:473, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:543, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)      

源碼:

@Override
protected List<Advisor> findCandidateAdvisors() {
  // 保持對XML配置的支援
  List<Advisor> advisors = super.findCandidateAdvisors();
  // 對注解方式的支援
  advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  return advisors;
}

public List<Advisor> buildAspectJAdvisors() {
  List<String> aspectNames = this.aspectBeanNames;

  if (aspectNames == null) {
    synchronized (this) {
      aspectNames = this.aspectBeanNames;
      if (aspectNames == null) {
        List<Advisor> advisors = new LinkedList<Advisor>();
        aspectNames = new LinkedList<String>();
        // 擷取所有的beanName
        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Object.class, true, false);
        // 周遊beanName找到對應的class對象
        for (String beanName : beanNames) {
          if (!isEligibleBean(beanName)) {
            continue;
          }
          // 根據beanName擷取class對象
          Class<?> beanType = this.beanFactory.getType(beanName);
          if (beanType == null) {
            continue;
          }
          // 判斷是否是切面類(判斷是否有@Aspect注解)
          if (this.advisorFactory.isAspect(beanType)) {
            aspectNames.add(beanName);
            AspectMetadata amd = new AspectMetadata(beanType, beanName);
            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
              MetadataAwareAspectInstanceFactory factory =
                  new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
              // 解析标 AspectJ 注解中的增強方法
              List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
              // 将建言添加到緩存中
              if (this.beanFactory.isSingleton(beanName)) {
                this.advisorsCache.put(beanName, classAdvisors);
              }
              else {
                this.aspectFactoryCache.put(beanName, factory);
              }
              advisors.addAll(classAdvisors);
            }
            ...
          }
        }
        this.aspectBeanNames = aspectNames;
        return advisors;
      }
    }
  }

  ...
  return advisors;
}      

切面類的解析其實就是去配置類中找加了​

​Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class​

​​注解的方法。

調用鍊路:

findAspectJAnnotationOnMethod:129, AbstractAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
getPointcut:215, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
getAdvisor:203, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
getAdvisors:136, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
buildAspectJAdvisors:109, BeanFactoryAspectJAdvisorsBuilder (org.springframework.aop.aspectj.annotation)      

源碼:

protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
  // 切點和建言的注解類
  Class<?>[] classesToLookFor = new Class<?>[] {
      Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
  for (Class<?> c : classesToLookFor) {
    // 找對應注解
    AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
    if (foundAnnotation != null) {
      return foundAnnotation;
    }
  }
  return null;
}      

通過調用鍊路我們可以看出,第一次解析切面類是在注冊第一個單執行個體Bean到容器的時候,會執行後置處理器AnnotationAwareAspectJAutoProxyCreator 的 postProcessBeforeInstantiation 方法中。後續的單執行個體Bean注冊到容器的時候會直接去緩存中的建言資訊,不會再次解析切面類了。

根據切點資訊生成增強器

我們找到增強器以後會統一封裝成InstantiationModelAwarePointcutAdvisorImpl類型,它是Advisor的子類。因為不同的增強所展現的邏輯是不同的,比如@Before (“test()”) 與 @After(“tes()”) 标簽的不同就是增強器增強的位置不同 ,是以就需要不同的增強器來完成不同的邏輯。

調用鍊路:

getAdvice:255, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
instantiateAdvice:160, InstantiationModelAwarePointcutAdvisorImpl (org.springframework.aop.aspectj.annotation)
<init>:106, InstantiationModelAwarePointcutAdvisorImpl (org.springframework.aop.aspectj.annotation)
getAdvisor:209, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
getAdvisors:136, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
buildAspectJAdvisors:109, BeanFactoryAspectJAdvisorsBuilder (org.springframework.aop.aspectj.annotation)
findCandidateAdvisors:90, AnnotationAwareAspectJAutoProxyCreator (org.springframework.aop.aspectj.annotation)
shouldSkip:103, AspectJAwareAdvisorAutoProxyCreator (org.springframework.aop.aspectj.autoproxy)
postProcessBeforeInstantiation:248, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsBeforeInstantiation:1045, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
resolveBeforeInstantiation:1019, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:473, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:543, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)      

源碼:

@Override
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
    MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  ...
  AbstractAspectJAdvice springAdvice;
  // 根據不同的注解類型封裝不同的增強器
  switch (aspectJAnnotation.getAnnotationType()) {
    case AtBefore:
      springAdvice = new AspectJMethodBeforeAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtAfter:
      springAdvice = new AspectJAfterAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtAfterReturning:
      springAdvice = new AspectJAfterReturningAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
      if (StringUtils.hasText(afterReturningAnnotation.returning())) {
        springAdvice.setReturningName(afterReturningAnnotation.returning());
      }
      break;
    case AtAfterThrowing:
      springAdvice = new AspectJAfterThrowingAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
      if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
        springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
      }
      break;
    case AtAround:
      springAdvice = new AspectJAroundAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtPointcut:
      if (logger.isDebugEnabled()) {
        logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
      }
      return null;
    default:
      throw new UnsupportedOperationException(
          "Unsupported advice type on method: " + candidateAdviceMethod);
  }

  // Now to configure the advice...
  springAdvice.setAspectName(aspectName);
  springAdvice.setDeclarationOrder(declarationOrder);
  String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
  if (argNames != null) {
    springAdvice.setArgumentNamesFromStringArray(argNames);
  }
  springAdvice.calculateArgumentBindings();
  return springAdvice;
}      

從函數中可以看到,Spring 會根據不同的注解生成不同的增強器,例如 @Before 會對應

AspectJMethodBeforeAdvice ,而在 AspectJMethodBeforeAdvice中完成了增強方法的邏輯。

Spring 源碼(六)Spring AOP源碼解析

MethodBeforeAdviceInterceptor

每個Advice又對應了一個MethodInterceptor,比如MethodBeforeAdvice就對應了MethodBeforeAdviceInterceptor。而我們對增強器的調用就是從MethodInterceptor的invoke方法開始的。 我們嘗試分析一下MethodBeforeAdvice的增強器實作:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
    // MethodBeforeAdvice 代表着置增強器 AspectJMethodBeforeAdvice
    private MethodBeforeAdvice advice;

    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        // 調用前置增強器的before方法
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        return mi.proceed();
    }
}

// AspectJMethodBeforeAdvice
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
    invokeAdviceMethod(getJoinPointMatch(), null, null);
}

protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
        actualArgs = null;
    }
    try {
        // 通過反射調用增強器
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        // TODO AopUtils.invokeJoinpointUsingReflection
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    }
    catch (IllegalArgumentException ex) {
        throw new AopInvocationException("Mismatch on arguments to advice method [" +
                this.aspectJAdviceMethod + "]; pointcut expression [" +
                this.pointcut.getPointcutExpression() + "]", ex);
    }
    catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
}      
整個擷取增強器的大緻流程:
  1. 周遊所有注冊到容器中的beanName,并根據beanName擷取對應的Class
  2. 根據Class找出所有聲明了@Aspect注解的類
  3. 對标記了@Aspect的類進行增強器的提取,其實就是去找加了​

    ​@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut​

    ​注解的方法。
  4. 将增強器封裝成InstantiationModelAwarePointcutAdvisorImpl類型
  5. 将提取結果添加到緩存中

建立增強Bean

初始化ProxyFactory

對于代理的建立和處理,Spring是委托給ProxyFactory去執行的,下面是對ProxyFactory進行初始化。調用鍊路:

createProxy:466, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
wrapIfNecessary:349, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
postProcessAfterInitialization:298, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsAfterInitialization:423, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1638, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:555, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:543, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)      

源碼:

protected Object createProxy(
        Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    
    ProxyFactory proxyFactory = new ProxyFactory();
    // 擷取目前類中的相關屬性
    proxyFactory.copyFrom(this);


    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 擷取到增強器
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 将增強器放到代理工廠中
    proxyFactory.addAdvisors(advisors);
    // 設定要代理的類
    proxyFactory.setTargetSource(targetSource);
    // 定制代理
    customizeProxyFactory(proxyFactory);

    // 用來控制代理工廠被配置後,是否允許修改通知,預設是false
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(getProxyClassLoader());
}      

執行過程:

  1. 擷取目前類中的屬性
  2. 添加代理接口
  3. 封裝Advisor并加入ProxyFactory中
  4. 設定代理類
  5. 執行自定義的函數customizeProxyFactory,在這裡可以對ProxyFactory進行進一步封裝
  6. 使用ProxyFactory擷取代理

建立 AopProxy 代理類

ProxyFactory建立代理首先需要确定使用JDK代理還是Cglib代理。

public Object getProxy(ClassLoader classLoader) {
  return createAopProxy().getProxy(classLoader);
}      

通過createAopProxy()方法确認需要使用那種代理,然後再去調用對應代理的getProxy()方法生成代理對象。

調用鍊路:

createAopProxy:51, DefaultAopProxyFactory (org.springframework.aop.framework)
createAopProxy:105, ProxyCreatorSupport (org.springframework.aop.framework)
getProxy:109, ProxyFactory (org.springframework.aop.framework)
createProxy:466, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
wrapIfNecessary:349, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
postProcessAfterInitialization:298, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsAfterInitialization:423, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1638, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:555, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:543, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)      

從調用鍊路上來看我們可以看到建立增強的Bean是在 後置處理器AnnotationAwareAspectJAutoProxyCreator 的 postProcessAfterInitialization 方法中,也就是完成初始化Bean之後執行。

源碼:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  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);
  }
  else {
    return new JdkDynamicAopProxy(config);
  }
}      

生成代理類

public Object getProxy(ClassLoader classLoader) {
  return createAopProxy().getProxy(classLoader);
}      

JdkDynamicAopProxy和ObjenesisCglibAopProxy建立代理的實作可以參考​​Cglib 與 JDK動态代理​​。

執行增強Bean

JdkDynamicAopProxy和CglibAopProxy采用了兩種不同的方式:

  • Proxy.newProxyInstance()->JdkDynamicAopProxy(繼承InvocationHandler接口).invoke(),然後比對通知類型調用通知(通知就是@Before、@After等等),最後調用目标方法
  • Enhancer.Callback,Callback類似于InvocationHandler,類DynamicAdvisedInterceptor繼承了Callback,它的intercept()方法就類似于invoke(),然後比對通知類型調用通知,最後調用目标方法。

不管是JdkDynamicAopProxy還是CglibAopProxy,最後都會将攔截鍊封裝到ReflectiveMethodInvocation類中,然後調用proceed()方法執行攔截連。最後通過MethodInterceptor.invoke()方法執行每個增強邏輯。大緻流程如下:

Spring 源碼(六)Spring AOP源碼解析

調用量鍊路:

before:33, LogAspect (com.xiaolyuh.aop.aspect)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeAdviceMethodWithGivenArgs:627, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invokeAdviceMethod:609, AbstractAspectJAdvice (org.springframework.aop.aspectj)
before:43, AspectJMethodBeforeAdvice (org.springframework.aop.aspectj)
invoke:51, MethodBeforeAdviceInterceptor (org.springframework.aop.framework.adapter)
proceed:168, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:47, AspectJAfterAdvice (org.springframework.aop.aspectj)
proceed:168, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:52, AfterReturningAdviceInterceptor (org.springframework.aop.framework.adapter)
proceed:168, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:62, AspectJAfterThrowingAdvice (org.springframework.aop.aspectj)
proceed:168, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:92, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:179, ReflectiveMethodInvocation (org.springframework.aop.framework)
intercept:671, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
div:-1, UserController$$EnhancerBySpringCGLIB$$a4147a00 (com.xiaolyuh.aop.controller)
contextTest:22, AopTest (com.xiaolyuh.aop)      

源碼:

@Override
public Object proceed() throws Throwable {
  //  執行完所有增強後執行切點方法(業務方法)
  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
  }

  // 擷取下一個要執行的攔截器 
  Object interceptorOrInterceptionAdvice =
      this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    // 動态比對
    InterceptorAndDynamicMethodMatcher dm =
        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    // 判斷是否需要執行攔截器
    if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
      return dm.interceptor.invoke(this);
    }
    else {
      // 動态比對失敗,該不執行攔截器,進入下一次循環
      return proceed();
    }
  }
  else {
    // 普通攔截器直接執行,比如:MethodBeforeAdviceInterceptor、AspectJAfterAdvice、AspectJAroundAdvice等
    // this作為參數傳遞,保證目前執行個體中調用鍊路的執行
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  }
}