開發與維運

Spring AOP源碼分析(Spring Framework 5.3.7-SNAPSHOT)

本篇內容以註解的形式使用Spring AOP,所以這裡容器使用的是AnnotationConfigApplicationContext

Spring Ioc容器的加載流程

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}
  • 首先是this(),此無參構造函數主要完成兩件事

    • 調用AnnotationConfigApplicationContext的一系列父類的無參構造函數,初始化相關的屬性,包括beanFactoryPostProcessors,beanFactory等重要屬性;
    • 通過AnnotatedBeanDefinitionReader註冊內置的postProcessor(實質是把<beanName,BeanDefinition>鍵值對放入DefaultListableBeanFactory的beanDefinitionMap屬性中)

      • AnnotationConfigUtils#registerPostProcessor會註冊以下後置處理器

        • ConfigurationClassPostProcessor(BeanDefinitionRegistryPostProcessor的實現類,主要解析主配置類、處理@Bean等註解)
        • AutowiredAnnotationBeanPostProcessor(SmartInstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor的實現類,本質是BeanPostProcessor)
        • CommonAnnotationBeanPostProcessor,設置@PostConstruct和@PreDestroy註解(在父類InitDestroyAnnotationBeanPostProcessor中)
        • 如果支持JPA,註冊PersistenceAnnotationBeanPostProcessor
        • EventListenerMethodProcessor
        • DefaultEventListenerFactory
    • 構造ClassPathBeanDefinitionScanner實例對象(構造函數setResourceLoader,把Spring ioc容器轉為ResourceLoader)
  • 註冊配置類

    • 把配置類放入DefaultListableBeanFactory的beanDefinitionMap屬性中
  • 刷新容器refresh()
  1. invokeBeanFactoryPostProcessors(beanFactory),主要完成的功能:往beanDefinitionNames中註冊@Bean註解標註的方法返回的對象,如:業務邏輯類,切面類,@Import註解引入的類,

    • invokeBeanDefinitionRegistryPostProcessors

參數為上一步獲取的後置處理器的bean集合,如:

- 首先從Spring容器中獲取ConfigurationClassPostProcessor對應的bean;
- 然後解析配置類,流程是:ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
    ```
    // 創建配置類的解析器
    // Parse each @Configuration class
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        // 開始解析
        parser.parse(candidates);
        parser.validate();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            // 創建配置類BeanDefinition的解析器
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // 解析@Bean註解標註的方法返回的對象,@Import註解引入的類,注入的對象
        this.reader.loadBeanDefinitions(configClasses);
    ```
    ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
    ```
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        // 解析@Bean註解標註的類返回的對象
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    // 解析@Import註解引入的類,注入的對象
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    ```
    - ConfigurationClassParser解析配置類,主要功能是填充configurationClasses屬性(key,value都是解析後的ConfigurationClass的實例)
    - 解析ConfigurationClass,主要是得到beanMethods,importBeanDefinitionRegistrars屬性值
    - ConfigurationClassBeanDefinitionReader#loadBeanDefinitions,主要功能是把上面解析得到的beanMethods註冊到beanDefinitionMap中,以及調用AspectJAutoproxyRegistrar的registerBeanDefinitions方法,把AnnotationAwareAspectJAutoProxyCreator註冊到beanDefinitionMap中
  1. registerBeanPostProcessors(beanFactory)
  • 實例化AnnotationAwareAspectJAutoProxyCreator,並加入AbstractBeanFactory的beanPostProcessors屬性中,
  • 往單例緩存池中加入internalAutoProxyCreator
  • 在獲取internalAutoProxyCreator的實例過程中,會調用doCreateBean#setBeanFactory的aware接口,初始化與AOP獲取advisors相關的一些類
    -總的邏輯;

    • 初始化BeanFactoryAdvisorRetrievalHelperAdapter對象
    • ReflectiveAspectJAdvisorFactory對象(解析切面,並獲取advisors集合)
    • BeanFactoryAspectJAdvisorsBuilderAdapter(AnnotationAwareAspectJAutoProxyCreator的內部類,其父類是BeanFactoryAspectJAdvisorsBuilder,作用是解析切面,並獲取advisors集合)對象
    • 源碼:
    • 首先調用AbstractAdvisorAutoProxyCreator的setBeanFactory方法
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        super.setBeanFactory(beanFactory);
        if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
            throw new IllegalArgumentException(
                    "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
        }
        initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
    }
    • 然後調用AnnotationAwareAspectJAutoProxyCreator的initBeanFactoryff
    @Override
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        if (this.aspectJAdvisorFactory == null) {
            this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        }
        // 內部類,它的父類是BeanFactoryAspectJAdvisorsBuilder
        this.aspectJAdvisorsBuilder =
                new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    }
    • 調用AbstractAdvisorAutoProxyCreator的initBeanFactory
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
    }
  1. finishBeanFactoryInitialization(beanFactory)
  • 創建剩餘非懶加載的bean,並存到單例緩存池,如:業務邏輯類,主配置類,切面類
  • 解析主配置類(如:aopConfig)時,在resolveBeforeInstantiation中AbstractAutoproxyCreator的postProcessBeforeInstantiation的shouldSkip中,

由ReflectiveAspectJAdvisorFactory#getAdvisors獲取advisors(不包含ExposeInvocationInterceptor)

- 源碼:
- 由ReflectiveAspectJAdvisorFactory(在上一步已創建對象)調用getAdvisors
```
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

List<Advisor> advisors = new ArrayList<>();
// 先獲取切面的通知方法(加了通知註解的方法)
for (Method method : getAdvisorMethods(aspectClass)) {
    // 調用以下方法,獲取每個通知的增強器,返回類型是InstantiationModelAwarePointcutAdvisorImpl
    Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
    if (advisor != null) {
        advisors.add(advisor);
    }
}
```
```
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {

    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }

    // 構造函數中會創建advice
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
```
```
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
        Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    this.declaredPointcut = declaredPointcut;
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    this.methodName = aspectJAdviceMethod.getName();
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    this.aspectInstanceFactory = aspectInstanceFactory;
    this.declarationOrder = declarationOrder;
    this.aspectName = aspectName;

    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut = Pointcuts.union(
                aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(
                this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
        this.lazy = true;
    }
    else {
        // A singleton aspect.
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 創建advice對象
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}
```
- InstantiationModelAwarePointcutAdvisorImpl的instantiateAdvice方法
```
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}
```
- 根據通知方法的註解,分別返回對應的AspectJXXXAdvice對象,@Around/@Before/@After/@Afterreturning/@AfterThrowing
```
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);

    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
        throw new AopConfigException("Advice must be declared inside an aspect type: " +
                "Offending method '" + candidateAdviceMethod + "' in class [" +
                candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
        logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;

    switch (aspectJAnnotation.getAnnotationType()) {
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            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;
        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;
        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;
}
```
  • 解析被代理的業務邏輯類(如:mathCalculator)時,在doCreateBean中AbstractAutoproxyCreator的postProcessAfterInitialization中獲取代理對象(advisors中添加ExposeInvocationInterceptor,

並調用AspectJAwareAdvisorAutoProxyCreator#sortAdvisors排序)

- 源碼:
- 獲取代理對象的入口
```
@Override
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);
        }
    }
    return bean;
}
```
```
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 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;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}
```
- createProxy

創建代理對象,把之前解析主配置類得到的advisors集合作為參數傳入,
在getProxy中,把ProxyCreatorSupport對象本身作為參數,傳入到DefaultAopProxyFactory#createAopProxy方法,返回ObjenesisCglibAopProxy對象(ProxyCreatorSupport對象作為參數),初始化ObjenesisCglibAopProxy的父類CglibAopProxy,設置advised的值為(ProxyCreatorSupport類型的對象,其中包含advisors集合)
image.png

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

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    // 依次調用父類AdvisedSupport,ProxyCreatorSupport的構造函數,
    // 分別聲明advisorChainFactory = new DefaultAdvisorChainFactory(),
    // aopProxyFactory = new DefaultAopProxyFactory()
    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);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // Use original ClassLoader if bean class not locally loaded in overriding class loader
    ClassLoader classLoader = getProxyClassLoader();
    if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
        classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
    }
    return proxyFactory.getProxy(classLoader);
}
public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}
- DefaultAopProxyFactory的createAopProxy,根據是否實現接口,採用cglib動態代理或JDK動態代理
```
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    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);
    }
}
```
- 最後返回代理對象

Spring AOP通知集合如何獲取以及代理對象的生成

image.png

  • 結合Spring Ioc容器的加載流程分析,在finishBeanFactoryInitialization這一步解析主配置類的bean,調用過程如下:

    • resolveBeforeInstantiation這一步,AbstractAutoProxyCreator的postProcessBeforeInstantiation方法
    • AspectJAwareAdvisorAutoProxyCreator#shouldSkip
    • AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
    • BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors(這裡BeanFactoryAspectJAdvisorsBuilder對象實例通過在registerBeanPostProcessors方法中創建)
    • ReflectiveAspectJAdvisorFactory調用相關類的方法

      • 如果是切面,由advisorFactory獲取當前切面的所有通知advisors,並存儲到advisorsCache(map類型,key是beanName,value是advisors)
      • 創建BeanFactoryAspectInstanceFactory對象factory
      • ReflectiveAspectJAdvisorFactory#getAdvisors(factory),參數是上一步中創建的factory

        • 創建LazySingletonAspectInstanceFactoryDecorator對象(創建MetadataAwareAspectInstanceFactory的裝飾器,便於它只被實例化一次!)
        • getAdvisorMethods

通過反射得到切面類的通知方法,並循環遍歷該集合,集合返回之前排序(按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的順序)

        - 返回InstantiationModelAwarePointcutAdvisorImpl對象,類型是Advisor
    - 如果是切面,最後把beanName加到aspectBeanNames(List類型,因為可以定義多個切面)中

image.png

    - 核心過程見上述的源碼
  • 解析業務邏輯類,獲取它的代理對象,獲取過程如下[核心過程見上述的源碼]:

    • doCreateBea -> initializingBean -> applyBeanPostProcessorsAfterInitialization
    • AbstractAutoProxyCreator#postProcessAfterInitialization
    • wrapIfNecessary 返回代理對象

      • AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean,從屬性aspectBeanNames,advisorsCache中獲取,他們賦值的地方在(finishBeanFactoryInitialization中,當beanName是aopConfig時,resolveBeforeInstantiation中解析切面)
      • extendAdvisors添加ExposeInvocationInterceptor.ADVISOR到集合的第一個
      • 把當前bean存入advisedBeans
      • createProxy

創建代理對象,把之前解析主配置類得到的advisors集合作為參數傳入,
在getProxy中,把ProxyCreatorSupport對象本身作為參數,傳入到DefaultAopProxyFactory#createAopProxy方法,返回ObjenesisCglibAopProxy對象(ProxyCreatorSupport對象作為參數),初始化ObjenesisCglibAopProxy的父類CglibAopProxy,設置advised的值為(ProxyCreatorSupport類型的對象,其中包含advisors集合)

        - 創建ProxyFactory對象proxyFactory,依次實例化:AdvisedSupport(創建默認的DefaultAdvisorChainFactory對象),ProxyCreatorSupport(創建默認的DefaultAopProxyFactory對象)
        - proxyFactory#getProxy
        - createAopProxy(),如果當前bean是接口,則返回JdkDynamicAopProxy對象,否則,返回ObjenesisCglibAopProxy對象
        - getProxy調用對應類的代理方法,生成bean的代理對象

Spring AOP攔截器鏈的生成

  • 以Cglib動態代理為例,CglibAopProxy執行攔截器鏈的生成
  • 當調用業務的邏輯方法時,代碼會進入CglibAopProxy的內部類DynamicAdvisedInterceptor,intercept方法

    • 源碼;
    @Override
        @Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Object target = null;
            TargetSource targetSource = this.advised.getTargetSource();
            try {
                if (this.advised.exposeProxy) {
                    // Make invocation available if necessary.
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                // 獲取攔截器鏈
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                // Check whether we only have one InvokerInterceptor: that is,
                // no real advice, but just reflective invocation of the target.
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    // We can skip creating a MethodInvocation: just invoke the target directly.
                    // Note that the final invoker must be an InvokerInterceptor, so we know
                    // it does nothing but a reflective operation on the target, and no hot
                    // swapping or fancy proxying.
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                }
                else {
                    // We need to create a method invocation...
                    // 開始鏈式的調用
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
    • 調用AdvisedSupport的方法
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }
    • 進入DefaultAdvisorChainFactory,主要是把前面解析得到的AspectJXXXAdvice集合,轉換為MethodInterceptor集合
    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, @Nullable Class<?> targetClass) {
    
        // This is somewhat tricky... We have to process introductions first,
        // but we need to preserve order in the ultimate list.
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        Advisor[] advisors = config.getAdvisors();
        List<Object> interceptorList = new ArrayList<>(advisors.length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        Boolean hasIntroductions = null;
    
        for (Advisor advisor : advisors) {
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    boolean match;
                    if (mm instanceof IntroductionAwareMethodMatcher) {
                        if (hasIntroductions == null) {
                            hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                        }
                        match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                    }
                    else {
                        match = mm.matches(method, actualClass);
                    }
                    if (match) {
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
    
        return interceptorList;
    }
    • 轉換用到了DefaultAdvisorAdapterRegistry,支持3種適配轉換器:MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter,ThrowsAdviceAdapter
    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[0]);
    }
    • MethodBeforeAdviceAdapter
    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }
    
    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
    • AfterReturningAdviceAdapter
    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof AfterReturningAdvice);
    }
    
    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
        return new AfterReturningAdviceInterceptor(advice);
    }
    • ThrowsAdviceAdapter
    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof ThrowsAdvice);
    }
    
    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        return new ThrowsAdviceInterceptor(advisor.getAdvice());
    }

Spring AOP的調用過程

  • MethodInvocation的鏈式生成過程,通過上一步獲取攔截器鏈之後,調用CglibMethodInvocation的proceed,觸發鏈式調用
  • 調用過程運用的軟件設計模式是職責鏈模式

    • 調用過程源碼:
    • new CglibMethodInvocation()
    public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
                Object[] arguments, @Nullable Class<?> targetClass,
                List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
    
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
    
            // Only use method proxy for public methods not derived from java.lang.Object
            this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
                    method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
                    !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
                    methodProxy : null);
        }
    • 調用父類ReflectiveMethodInvocation的構造函數
    protected ReflectiveMethodInvocation(
            Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
            @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
    
        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }
    • 開始調用CglibMethodInvocation的proceed方法
    @Override
        @Nullable
        public Object proceed() throws Throwable {
            try {
                return super.proceed();
            }
            catch (RuntimeException ex) {
                throw ex;
            }
            catch (Exception ex) {
                if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
                        KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
                    // Propagate original exception if declared on the target method
                    // (with callers expecting it). Always propagate it for Kotlin code
                    // since checked exceptions do not have to be explicitly declared there.
                    throw ex;
                }
                else {
                    // Checked exception thrown in the interceptor but not declared on the
                    // target method signature -> apply an UndeclaredThrowableException,
                    // aligned with standard JDK dynamic proxy behavior.
                    throw new UndeclaredThrowableException(ex);
                }
            }
        }
    • 調用父類ReflectiveMethodInvocation的proceed方法,不斷地從增強器中獲取增強器,在ReflectiveMethodInvocation與子類CglibMethodInvocation來回調用,而且通過在各個MethodInterceptor實現類中實現鏈式調用
    @Override
    @Nullable
    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);
        }
    }
    • 按照調用棧從底向上,依次為ExposeInvocationInterceptor:
    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = invocation.get();
        invocation.set(mi);
        try {
            return mi.proceed();
        }
        finally {
            invocation.set(oldInvocation);
        }
    }
    • AspectJAroundAdvice(如果有環繞通知)
    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
        JoinPointMatch jpm = getJoinPointMatch(pmi);
        return invokeAdviceMethod(pjp, jpm, null, null);
    }
    • MethodBeforeAdviceInterceptor
    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
    • AspectJAfterAdvice
    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        finally {
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }
    • AfterReturningAdviceInterceptor
    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }
    • AspectJAfterThrowingAdvice
    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        catch (Throwable ex) {
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(getJoinPointMatch(), null, ex);
            }
            throw ex;
        }
    }
    • 當增強器都遍歷完,則調用業務方法
    // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
    • 最後依次出棧,完成整個鏈式調用

AOP運用的設計模式

  • 職責鏈模式的出現背景是:把請求的發起者與處理者解耦,也就是說,客戶端只管發送請求,至於請求該誰處理由請求鏈決定
  • 狀態模式與職責鏈的不同在於:狀態的改變條件,在類中是已經寫好的,無法在客戶端靈活設置
  • AOP攔截器鏈的執行過程,請求處理者的攔截器鏈是在切面中定義,可以靈活設置,請求沿著鏈傳遞(只是aop約定好了前置、後置、正常返回,異常返回這些切面邏輯)

總結

  • AOP攔截器鏈的執行,運用的軟件設計模式

    • 責任鏈模式
  • 攔截器鏈advisor轉換為MethodInterceptor的邏輯

    • 實現了MethodInterceptor接口

      • AspectJAfterThrowingAdvice
      • AspectJAfterAdvice
    • 未實現MethodInterceptor接口

      • AspectJAfterReturningAdvice
      • AspectJMethodBeforeAdvice
  • BeanFactoryAspectJAdvisorsBuilder中的advisorsCache在何時賦值?

    • BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法,同步塊雙重檢查鎖定中,先獲取advisors,然後put到cache中

待細化

  • ReflectiveAspectJAdvisorFactory中的getAdvisorMethods()對切面中定義的@Befre/@Around/@After/@AfterReturning/@AfterThrowing註解標註的方法排序
  • 使用

    • AspectJ指示器:execution/@args/@annotations......
    • @AfterReturning可設置returing()屬性
    • @AfterThrowing可以設置throwing()屬性
  • @Around註解以及標註的方法的調用邏輯
  • 多切面,多個被攔截方法

Leave a Reply

Your email address will not be published. Required fields are marked *