• Spring异步调用原理及SpringAop拦截器链原理


    一、Spring异步调用底层原理

      开启异步调用只需一个注解@EnableAsync

    @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。

    @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做了哪些事情。

    @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是哪里来的呢、默认值是什么?接着继续向父级探索。

    @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类型的实例呦。

      进入异步实现的正题了,当然是好好研究一下AsyncAnnotationBeanPostProcessor这个后置处理器做了哪些事情了。

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

      1、添加一个AOP advisor(AsyncAnnotationAdvisor),识别带有@Async注解或者指定类型注解的方法,创建代理类。

      2、找一个合适的TaskExecutor来异步调用带有@Async注解或者指定类型注解的方法。

      3、如果方法在异步调用过程中抛出异常,将使用合适的ExceptionHandler进行处理。

      看到这里,已经有两个疑问了。AsyncAnnotationAdvisor做了什么?如何创建的异步调用代理类?

      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创建代理对象。

    二、正确实现异步调用

      1、启动类新增注解@EnableAsync

      2、通过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;
            }
        }
    }

      3、成员方法异步调用、内部类方法异步调用、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();
        }
    }

     三、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实例。

      简单总结一下获取拦截器链的过程, 如下。

      1、从缓存中获取当前方法的拦截器链
      2、若缓存未命中,则调用 getInterceptorsAndDynamicInterceptionAdvice 获取拦截器链
      3、遍历通知器列表
      4、对于 PointcutAdvisor 类型的通知器,这里要调用通知器所持有的切点(Pointcut)对类和方法进行匹配,匹配成功说明应向当前方法织入通知逻辑
      5、调用 getInterceptors 方法对非 MethodInterceptor 类型的通知进行转换
      6、返回拦截器数组,并在随后存入缓存中

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

    四、参考

       Spring AOP 源码分析 - 拦截器链的执行过程

    五、总结

      至此,Spring异步调用原理及SpringAop拦截器链都已经分析完毕,希望对大家使用spring异步调用有所帮助。另外我自己也重新温习了spring aop相关的知识,也希望大家对spring aop有一个新的认识。如果有需要源码的同学,请f访问我的github:Spring异步调用原理及实现方案demo

      

  • 相关阅读:
    解决Oracle XE报错ORA-12516(oracle回话数超出限制)
    端口被占用如何处理
    ORACLE initialization or shutdown in progress 错误解决办法
    oracle的闪回功能
    Linux入门
    oracle字段like多个条件
    navicat常用快捷键与SQL基本使用
    Oracle四舍五入,向上取整,向下取整
    无限循环小数化分数
    筛选素数
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/10549849.html
Copyright © 2020-2023  润新知