Spring異步調用原理及SpringAop攔截器鏈原理

1、Spring異步調用底層原理

  開啓異步調用只需一個註解@EnableAsynchtml

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

    /**
     * Indicate the 'async' annotation type to be detected at either class
     * or method level.
     * <p>By default, both Spring's @{@link Async} annotation and the EJB 3.1
     * {@code @javax.ejb.Asynchronous} annotation will be detected.
     * <p>This attribute exists so that developers can provide their own
     * custom annotation type to indicate that a method (or all methods of
     * a given class) should be invoked asynchronously.
     */
    Class<? extends Annotation> annotation() default Annotation.class;

    /**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies.
     * <p><strong>Applicable only if the {@link #mode} is set to {@link AdviceMode#PROXY}</strong>.
     * <p>The default is {@code false}.
     * <p>Note that setting this attribute to {@code true} will affect <em>all</em>
     * Spring-managed beans requiring proxying, not just those marked with {@code @Async}.
     * For example, other beans marked with Spring's {@code @Transactional} annotation
     * will be upgraded to subclass proxying at the same time. This approach has no
     * negative impact in practice unless one is explicitly expecting one type of proxy
     * vs. another &mdash; for example, in tests.
     */
    boolean proxyTargetClass() default false;

    /**
     * Indicate how async advice should be applied.
     * <p><b>The default is {@link AdviceMode#PROXY}.</b>
     * Please note that proxy mode allows for interception of calls through the proxy
     * only. Local calls within the same class cannot get intercepted that way; an
     * {@link Async} annotation on such a method within a local call will be ignored
     * since Spring's interceptor does not even kick in for such a runtime scenario.
     * For a more advanced mode of interception, consider switching this to
     * {@link AdviceMode#ASPECTJ}.
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     * Indicate the order in which the {@link AsyncAnnotationBeanPostProcessor}
     * should be applied.
     * <p>The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run
     * after all other post-processors, so that it can add an advisor to
     * existing proxies rather than double-proxy.
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

  AsyncConfigurationSelector的做用是從兩個異步配置類中選擇一個來完成底層異步代理的工做。這個兩個配置類分別是AspectJAsyncConfiguration、ProxyAsyncConfiguration。java

@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
        case PROXY:
            return new String[] {ProxyAsyncConfiguration.class.getName()};
        case ASPECTJ:
            return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
        default:
            return null;
    }
}

  其中adviceMode就是@EnableAsync註解中mode()方法的值,默認是"PROXY"。接下來着重看一下ProxyAsyncConfiguration作了哪些事情。git

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

    @Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
        Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
        AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
        bpp.configure(this.executor, this.exceptionHandler);
        Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
        if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
            bpp.setAsyncAnnotationType(customAsyncAnnotation);
        }
        bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
        bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
        return bpp;
    }

}

  ProxyAsyncConfiguration主要是建立了一個基於異步調用的後置處理器(AsyncAnnotationBeanPostProcessor),改BPP中設置了executor(異步線程池)、exceptionHandler(異常處理器)、AsyncAnnotationType(異步註解類型)、proxyTargetClass(代理建立模式)、order(後置處理器執行順序)。那麼executor和exceptionHandler是哪裏來的呢、默認值是什麼?接着繼續向父級探索。github

@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {

    .....
    
    /**
     * Collect any {@link AsyncConfigurer} beans through autowiring.
     */
    @Autowired(required = false)
    void setConfigurers(Collection<AsyncConfigurer> configurers) {
        if (CollectionUtils.isEmpty(configurers)) {
            return;
        }
        if (configurers.size() > 1) {
            throw new IllegalStateException("Only one AsyncConfigurer may exist");
        }
        AsyncConfigurer configurer = configurers.iterator().next();
        this.executor = configurer::getAsyncExecutor;
        this.exceptionHandler = configurer::getAsyncUncaughtExceptionHandler;
    }

}

  因而可知,executor和exceptionHandler能夠經過AsyncConfigurer自定義配置。須要注意的是,spring容器中只能有一個AsyncConfigurer類型的實例呦。spring

  進入異步實現的正題了,固然是好好研究一下AsyncAnnotationBeanPostProcessor這個後置處理器作了哪些事情了。c#

public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {

    ....

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        super.setBeanFactory(beanFactory);

        AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
        if (this.asyncAnnotationType != null) {
            advisor.setAsyncAnnotationType(this.asyncAnnotationType);
        }
        advisor.setBeanFactory(beanFactory);
        this.advisor = advisor;
    }

}

  一、添加一個AOP advisor(AsyncAnnotationAdvisor),識別帶有@Async註解或者指定類型註解的方法,建立代理類。數組

  二、找一個合適的TaskExecutor來異步調用帶有@Async註解或者指定類型註解的方法。緩存

  三、若是方法在異步調用過程當中拋出異常,將使用合適的ExceptionHandler進行處理。springboot

  看到這裏,已經有兩個疑問了。AsyncAnnotationAdvisor作了什麼?如何建立的異步調用代理類?app

  AsyncAnnotationAdvisor實現原理

  你們都知道,Spring Aop中,一個advisor包含一個advice(通知)、pointcut(切點)。

  建立advice

protected Advice buildAdvice(
        @Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

    AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
    interceptor.configure(executor, exceptionHandler);
    return interceptor;
}

  AnnotationAsyncExecutionInterceptor是一個方法攔截器,父級接口是咱們最熟悉的org.aopalliance.intercept.MethodInterceptor。這個攔截器有個優秀的功能,能夠根據不一樣的方法選擇不一樣的taskexecutor來異步執行,即Async#value()方法的值。

public Object invoke(final MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
    final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

    AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
    if (executor == null) {
        throw new IllegalStateException(
                "No executor specified and no default executor set on AsyncExecutionInterceptor either");
    }

    Callable<Object> task = () -> {
        try {
            Object result = invocation.proceed();
            if (result instanceof Future) {
                return ((Future<?>) result).get();
            }
        }
        catch (ExecutionException ex) {
            handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
        }
        catch (Throwable ex) {
            handleError(ex, userDeclaredMethod, invocation.getArguments());
        }
        return null;
    };

    return doSubmit(task, executor, invocation.getMethod().getReturnType());
}

  攔截器的invoke方法看一下瞬間豁然開朗,尋找方法對應的橋接方法、選擇一個合適的異步執行的executor、建立Callback實例(異常的處理)、提交異步調用任務到executor中。

  建立pointcut

public interface Pointcut {

    /**
     * Return the ClassFilter for this pointcut.
     * @return the ClassFilter (never {@code null})
     */
    ClassFilter getClassFilter();

    /**
     * Return the MethodMatcher for this pointcut.
     * @return the MethodMatcher (never {@code null})
     */
    MethodMatcher getMethodMatcher();


    /**
     * Canonical Pointcut instance that always matches.
     */
    Pointcut TRUE = TruePointcut.INSTANCE;

}

public interface Pointcut {

    /**
     * Return the ClassFilter for this pointcut.
     * @return the ClassFilter (never {@code null})
     */
    ClassFilter getClassFilter();

    /**
     * Return the MethodMatcher for this pointcut.
     * @return the MethodMatcher (never {@code null})
     */
    MethodMatcher getMethodMatcher();


    /**
     * Canonical Pointcut instance that always matches.
     */
    Pointcut TRUE = TruePointcut.INSTANCE;

}

  一個切點主要包含兩個對象ClassFilter(class過濾器)、MethodMatcher(方法匹配器)。AnnotationMatchingPointcut主要匹配注有@Async或者指定類型註解的class或者方法。

    異步代理類調用建立過程

  繼續回到AsyncAnnotationBeanPostProcessor這個後置處理器,父類AbstractBeanFactoryAwareAdvisingPostProcessor是和AbstractAutoProxyCreator(Spring Aop中最多見的建立Aop Proxy的BPP)同一級別的,主要是曝光代理對象的class、強制設置target-class mode。

@Override
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
    if (this.beanFactory != null) {
        AutoProxyUtils.exposeTargetClass(this.beanFactory, beanName, bean.getClass());
    }

    ProxyFactory proxyFactory = super.prepareProxyFactory(bean, beanName);
    if (!proxyFactory.isProxyTargetClass() && this.beanFactory != null &&
            AutoProxyUtils.shouldProxyTargetClass(this.beanFactory, beanName)) {
        proxyFactory.setProxyTargetClass(true);
    }
    return proxyFactory;
}

  如何判斷bean是否須要建立proxy呢?

@Override
protected boolean isEligible(Object bean, String beanName) {
    return (!AutoProxyUtils.isOriginalInstance(beanName, bean.getClass()) &&
            super.isEligible(bean, beanName));
}
AbstractAdvisingBeanPostProcessor.java

protected boolean isEligible(Class<?> targetClass) {
    Boolean eligible = this.eligibleBeans.get(targetClass);
    if (eligible != null) {
        return eligible;
    }
    if (this.advisor == null) {
        return false;
    }
    eligible = AopUtils.canApply(this.advisor, targetClass);
    this.eligibleBeans.put(targetClass, eligible);
    return eligible;
}
AopUtils.java

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else 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;
    }
}

  首先當前處理的bean是最原始的實例,而後經過advisor的pointcut去判斷。

  繼續追蹤父級AbstractAdvisingBeanPostProcessor。

public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (this.advisor == null || bean instanceof AopInfrastructureBean) {
        // Ignore AOP infrastructure such as scoped proxies.
        return bean;
    }

    if (bean instanceof Advised) {
        Advised advised = (Advised) bean;
        if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
            // Add our local Advisor to the existing proxy's Advisor chain...
            if (this.beforeExistingAdvisors) {
                advised.addAdvisor(0, this.advisor);
            }
            else {
                advised.addAdvisor(this.advisor);
            }
            return bean;
        }
    }

    if (isEligible(bean, beanName)) {
        ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
        if (!proxyFactory.isProxyTargetClass()) {
            evaluateProxyInterfaces(bean.getClass(), proxyFactory);
        }
        proxyFactory.addAdvisor(this.advisor);
        customizeProxyFactory(proxyFactory);
        return proxyFactory.getProxy(getProxyClassLoader());
    }

    // No proxy needed.
    return bean;
}

  這個抽象類中實現了BPP的postProcessAfterInitialization方法。若是bean是Advised,則將AsyncAnnotationAdvisor添加到Advised實例中去;若是是一個能夠建立異步調用代理的bean,經過ProxyFactory建立代理對象。

2、正確實現異步調用

  一、啓動類新增註解@EnableAsync

  二、經過AsyncConfigurerSupport建立異步調用線程池,合理設置相關配置參數,以下。

@Configuration
public class MyAsyncConfigurer extends AsyncConfigurerSupport {
    private static Logger LOGGER = LoggerFactory.getLogger(MyAsyncConfigurer.class);

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(2);
        taskExecutor.setMaxPoolSize(4);
        taskExecutor.setQueueCapacity(10);
        taskExecutor.setRejectedExecutionHandler((runnable, executor) -> LOGGER.error("異步線程池拒絕任務..." + runnable));
        taskExecutor.setThreadFactory(new MyAsyncThreadFactory());
        taskExecutor.initialize();
        return taskExecutor;
    }

    static class MyAsyncThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        MyAsyncThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = "myasync-pool-" +
                    poolNumber.getAndIncrement() +
                    "-thread-";
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
}

  三、成員方法異步調用、內部類方法異步調用、spring retry功能整合到異步調用

@Component
public class MyAsyncTask {

    private static Logger LOGGER = LoggerFactory.getLogger(MyAsyncConfigurer.class);

    /**
     * Lazy 功能
     *
     * @see DefaultListableBeanFactory#resolveDependency(DependencyDescriptor, String, Set, TypeConverter)
     * <p>
     * Spring Bean建立-解決依賴 參考連接:https://blog.csdn.net/finalcola/article/details/81537380
     */
    @Lazy
    @Autowired
    private MyInnerAsyncTask myInnerAsyncTask;

    @Autowired
    private AsyncWrapped asyncWrapped;

    @Async
    public void async() {
        LOGGER.error("async");
    }

    public void asyncInner() {
        myInnerAsyncTask.async();
    }

    public void asyncWrapped() {
        asyncWrapped.asyncProcess(() -> LOGGER.error("async wrapped"), null, null);
    }

    public void asyncWrappedWithRetry() {
        Retry retry = new Retry(2, 1000);
        asyncWrapped.asyncProcess(() -> {
            throw new RuntimeException("async wrapped with retry");
        }, null, retry);
    }

    public void asyncWrappedWithRetry2() {
        try {
            asyncWrapped.asyncProcess(() -> {
                throw new RuntimeException("async wrapped with retry2");
            });
        } catch (Exception e) {
            LOGGER.error("異步調用異常...", e);
        }
    }

    private class MyInnerAsyncTask {
        @Async
        public void async() {
            LOGGER.error("async inner");
        }
    }

    @Configuration
    public static class MyAsyncTaskConfiguration {
        @Bean
        public MyInnerAsyncTask myInnerAsyncTask(MyAsyncTask myAsyncTask) {
            return myAsyncTask.new MyInnerAsyncTask();
        }
    }
}
@Component
public class AsyncWrapped {
    protected static Logger LOGGER = LoggerFactory.getLogger(AsyncWrapped.class);

    @Async
    public void asyncProcess(Runnable runnable, Callback callback, Retry retry) {
        try {
            if (retry == null) {
                retry = new Retry(1);
            }
            retry.execute(ctx -> {
                runnable.run();
                return null;
            }, ctx -> {
                if (callback != null) {
                    callback.call();
                }
                return null;
            });
        } catch (Exception e) {
            LOGGER.error("異步調用異常...", e);
        }
    }

    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void asyncProcess(Runnable runnable) throws Exception {
        System.out.println("重試中...");
        runnable.run();
    }

    @FunctionalInterface
    public interface Runnable {
        void run() throws Exception;
    }

    @FunctionalInterface
    public interface Callback {
        void call();
    }
}

 3、Spring Aop攔截器鏈

  原本沒有寫這塊的東西,Spring異步調用整合了Spring Retry功能以後,就像看一下兩者是如何協調工做的。

  開啓異步和重試功能,僅須要加上這兩個註解@EnableAsync、@EnableRetry。

  你們能夠看一下RetryConfiguration這個類,直接告訴你們了,它是一個advisor,直接註冊到spring容器當中的。AbstractAutoProxyCreator會拿到這個advisor,對具備@Retryable註解的bean建立代理類。分析流程和AsyncAnnotationAdvisor一致,你們能夠按照上面講過的流程分析一下Spring Retry的底層實現原理,這裏就不詳細說明了。

  以下是AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization()方法。

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

  

  上圖中AnnotationAwareAspectJAutoProxyCreator是AbstractAdvisorAutoProxyCreator的實例。也就是說AbstractAdvisorAutoProxyCreator類型的後置處理器優先於AsyncAnnotationBeanPostProcessor類型的後置處理器執行。AbstractAdvisorAutoProxyCreator BPP經過BeanFactoryAdvisorRetrievalHelper從當前的BeanFactory中拿到全部的advisor。

  

  而後針對當前的bean(beanName = asyncWrapped )篩選出合適的advisor集合(包含RetryConfiguration實例)。最後是經過ProxyFactory建立的代理類,具體以下。

  

  ProxyFactory經過默認AopProxyFactory即DefaultAopProxyFactory來建立Aop Proxy。

  

  到這裏,beanName = asyncWrapped 關於Retryable的代理對象已經建立完畢,並返回代理對象替代當前的bean。而後繼續到AsyncAnnotationBeanPostProcessor#postProcessAfterInitialization()方法,處理關於帶有@Async註解的bean。

//若是是advised
if
(bean instanceof Advised) { Advised advised = (Advised) bean; if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) { // Add our local Advisor to the existing proxy's Advisor chain... if (this.beforeExistingAdvisors) { advised.addAdvisor(0, this.advisor); } else { advised.addAdvisor(this.advisor); } return bean; } } //這裏的邏輯不會執行了 if (isEligible(bean, beanName)) { ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName); if (!proxyFactory.isProxyTargetClass()) { evaluateProxyInterfaces(bean.getClass(), proxyFactory); } proxyFactory.addAdvisor(this.advisor); customizeProxyFactory(proxyFactory); return proxyFactory.getProxy(getProxyClassLoader()); }

  之前總覺得多個註解,就會屢次建立代理,一層一層嵌套。如今明白了,是經過攔截器鏈來完成的。此時beanName = asyncWrapped對應的bean已是Advised類型的實例了,而後將AsyncAnnotationAdvisor實例添加到Advised實例的advisors集合中。

  爲啥beanName = asyncWrapped對應的bean是Advised類型的實例?那還要從對beanName = asyncWrapped的bean建立代理類提及。那麼接着回到經過DefaultAopProxyFactory來建立Aop Proxy。這裏看一下CglibAopProxy,JdkDynamicAopProxy請自行查看。如下代碼來自CglibAopProxy#getProxy()方法。

......
//設置須要代理的接口 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(
this.advised)); ......
//獲取callbacks Callback[] callbacks
= getCallbacks(rootClass);
......
//設置callback filter
enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); .....

  設置須要代理的接口,除了目標類包含的接口,還須要添加一些額外的接口。以下是AopProxyUtils#completeProxiedInterfaces()方法中的內容。

......
if (addSpringProxy) {
    proxiedInterfaces[index] = SpringProxy.class;
    index++;
}
if (addAdvised) {
    proxiedInterfaces[index] = Advised.class;
    index++;
}
if (addDecoratingProxy) {
    proxiedInterfaces[index] = DecoratingProxy.class;
}
......

  看到了Advised.class哈,這就是爲啥最終的代理對象是Advised類型的實例了。

  獲取callbacks集合注意this.advisedDispatcher在數組中的索引是4,下面會用到。

Callback[] mainCallbacks = new Callback[] {
            aopInterceptor,  // for normal advice
            targetInterceptor,  // invoke target without considering advice, if optimized
            new SerializableNoOp(),  // no override for methods mapped to this
            targetDispatcher, this.advisedDispatcher,
            new EqualsInterceptor(this.advised),
            new HashCodeInterceptor(this.advised)
    };

  設置callback filters,以下是ProxyCallbackFilter#accept(Method method)部分源碼。

......
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        if (logger.isTraceEnabled()) {
            logger.trace("Method is declared on Advised interface: " + method);
        }
        return DISPATCH_ADVISED;
    }
......

  ProxyCallbackFilter的做用主要是根據不一樣類型的method,返回callbacks數組的索引。上面的DISPATCH_ADVISED變量的值是4

  這個AdvisedDispatcher是幹什麼的呢?

//Dispatcher for any methods declared on the Advised class.
private static class AdvisedDispatcher implements Dispatcher, Serializable { private final AdvisedSupport advised; public AdvisedDispatcher(AdvisedSupport advised) { this.advised = advised; } @Override public Object loadObject() throws Exception { return this.advised; } }

  也就是若是method是Advised.class聲明的,則使用AdvisedDispatcher進行分發。

AsyncAnnotationBeanPostProcessor#postProcessAfterInitialization()

//若是是advised
if (bean instanceof Advised) {
    Advised advised = (Advised) bean;
    if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
        // Add our local Advisor to the existing proxy's Advisor chain...
        if (this.beforeExistingAdvisors) {
            advised.addAdvisor(0, this.advisor);
        }
        else {
            advised.addAdvisor(this.advisor);
        }
        return bean;
    }
}

  上面的advised.addAdvisor(0, this.advisor); 至關於以下代碼。

//spring aop cglib代理對象
public
class XXXX$$EnhancerBySpringCGLIB$$8f47b115 implements Advised { private org.springframework.cglib.proxy.Dispatcher advisedDispatcher;//AdvisedDispatcher實例 ...... @Override public void addAdvisor(int pos, Advisor advisor) throws AopConfigException() { advisedDispatcher.loadObject().addAdvisor(pos, advisor); } ...... }

   還須要補充的一個地方就是callbacks數組中有個aopInterceptor,對應的類型是DynamicAdvisedInterceptor(General purpose AOP callback. Used when the target is dynamic or when the proxy is not frozen.)。

    

  如上圖所示,intercept方法中會經過advised(AdvisedSupport type, The configuration used to configure this proxy.)實例獲取一個攔截器鏈,若是不爲空,則返回一個CglibMethodInvocation實例。

  簡單總結一下獲取攔截器鏈的過程, 以下。

  一、從緩存中獲取當前方法的攔截器鏈
  二、若緩存未命中,則調用 getInterceptorsAndDynamicInterceptionAdvice 獲取攔截器鏈
  三、遍歷通知器列表
  四、對於 PointcutAdvisor 類型的通知器,這裏要調用通知器所持有的切點(Pointcut)對類和方法進行匹配,匹配成功說明應向當前方法織入通知邏輯
  五、調用 getInterceptors 方法對非 MethodInterceptor 類型的通知進行轉換
  六、返回攔截器數組,並在隨後存入緩存中

  CglibMethodInvocation的父類是ReflectiveMethodInvocation,ReflectiveMethodInvocation 貫穿於攔截器鏈執行的始終。

public class ReflectiveMethodInvocation implements ProxyMethodInvocation {

    private int currentInterceptorIndex = -1;

    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;
            /*
             * 調用具備三個參數(3-args)的 matches 方法動態匹配目標方法,
             * 兩個參數(2-args)的 matches 方法用於靜態匹配
             */
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                // 調用攔截器邏輯
                return dm.interceptor.invoke(this);
            }
            else {
                // 若是匹配失敗,則忽略當前的攔截器
                return proceed();
            }
        }
        else {
            // 調用攔截器邏輯,並傳遞 ReflectiveMethodInvocation 對象
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

  因此整個攔截器鏈的調用流程大約長這樣(盜圖一張)。

  

    你們在寫MethodInterceptor 的時候注意了,必定要調用MethodInvocation 的 proceed()方法,不然不能執行攔截器鏈。

public SelfMethodInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //前置邏輯
Object ret=invocation.proceed(); //錯誤的寫法,沒法執行攔截器鏈 //Object ret = invocation.getMethod().invoke(invocation.getThis(), invocation.getArguments()); //後置邏輯 return ret; } }

4、參考

   Spring AOP 源碼分析 - 攔截器鏈的執行過程

5、總結

  至此,Spring異步調用原理及SpringAop攔截器鏈都已經分析完畢,但願對你們使用spring異步調用有所幫助。另外我本身也從新溫習了spring aop相關的知識,也但願你們對spring aop有一個新的認識。若是有須要源碼的同窗,請f訪問個人github:Spring異步調用原理及實現方案demo

相關文章
相關標籤/搜索