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 {....@Overridepublic 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.javaprotected 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.javapublic 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);@Overridepublic 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-";}@Overridepublic 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@Autowiredprivate MyInnerAsyncTask myInnerAsyncTask;@Autowiredprivate AsyncWrapped asyncWrapped;@Asyncpublic 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 {@Asyncpublic void async() {LOGGER.error("async inner");}}@Configurationpublic static class MyAsyncTaskConfiguration {@Beanpublic MyInnerAsyncTask myInnerAsyncTask(MyAsyncTask myAsyncTask) {return myAsyncTask.new MyInnerAsyncTask();}}
}
@Component
public class AsyncWrapped {protected static Logger LOGGER = LoggerFactory.getLogger(AsyncWrapped.class);@Asyncpublic 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();}@FunctionalInterfacepublic interface Runnable {void run() throws Exception;}@FunctionalInterfacepublic 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 advicetargetInterceptor,  // invoke target without considering advice, if optimizednew SerializableNoOp(),  // no override for methods mapped to thistargetDispatcher, 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;}@Overridepublic 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实例 ......@Overridepublic 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

 

  

转载于:https://www.cnblogs.com/hujunzheng/p/10549849.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531198.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC源码——Root WebApplicationContext

Spring MVC源码——Root WebApplicationContext 打算开始读一些框架的源码,先拿 Spring MVC 练练手,欢迎点击这里访问我的源码注释, SpringMVC官方文档一开始就给出了这样的两段示例: WebApplicationInitializer示例: public class MyWebApplicationInitializer implements Web…

Spring MVC源码——Servlet WebApplicationContext

上一篇笔记(Spring MVC源码——Root WebApplicationContext)中记录了下 Root WebApplicationContext 的初始化代码.这一篇来看 Servlet WebApplicationContext 的初始化代码 DispatcherServlet 是另一个需要在 web.xml 中配置的类, Servlet WebApplicationContext 就由它来创建…

Springboot源码——应用程序上下文分析

前两篇(Spring MVC源码——Root WebApplicationContext 和 Spring MVC源码——Servlet WebApplicationContext)讲述了springmvc项目创建上下文的过程&#xff0c;这一篇带大家了解一下springboot项目创建上下文的过程。 SpringApplication引导类 SpringApplication类用于启动或…

基于zookeeper实现分布式配置中心(一)

最近在学习zookeeper&#xff0c;发现zk真的是一个优秀的中间件。在分布式环境下&#xff0c;可以高效解决数据管理问题。在学习的过程中&#xff0c;要深入zk的工作原理&#xff0c;并根据其特性做一些简单的分布式环境下数据管理工具。本文首先对zk的工作原理和相关概念做一下…

基于zookeeper实现分布式配置中心(二)

上一篇&#xff08;基于zookeeper实现分布式配置中心&#xff08;一&#xff09;&#xff09;讲述了zookeeper相关概念和工作原理。接下来根据zookeeper的特性&#xff0c;简单实现一个分布式配置中心。 配置中心的优势 1、各环境配置集中管理。 2、配置更改&#xff0c;实时推…

Redis分布式锁实战

背景 目前开发过程中&#xff0c;按照公司规范&#xff0c;需要依赖框架中的缓存组件。不得不说&#xff0c;做组件的大牛对CRUD操作的封装&#xff0c;连接池、缓存路由、缓存安全性的管控都处理的无可挑剔。但是有一个小问题&#xff0c;该组件没有对分布式锁做实现&#xff…

基于RobotFramework实现自动化测试

Java robotframework seleniumlibrary 使用Robot Framework Maven Plugin&#xff08;http://robotframework.org/MavenPlugin/&#xff09;执行自动化测试chromedriver下载&#xff1a; http://chromedriver.storage.googleapis.com/index.htmlchromedriver和chrome版本对应…

Springboot国际化信息(i18n)解析

国际化信息理解 国际化信息也称为本地化信息 。 Java 通过 java.util.Locale 类来表示本地化对象&#xff0c;它通过 “语言类型” 和 “国家/地区” 来创建一个确定的本地化对象 。举个例子吧&#xff0c;比如在发送一个具体的请求的时候&#xff0c;在header中设置一个键值对…

C语言一看就能上手的干货!你确定你不来看吗?

本地环境设置 如果您想要设置 C 语言环境&#xff0c;您需要确保电脑上有以下两款可用的软件&#xff0c;文本编辑器和 C 编译器。 文本编辑器 这将用于输入您的程序。文本编辑器包括 Windows Notepad、OS Edit command、Brief、Epsilon、EMACS 和 vim/vi。文本编辑器的名称…

10万码农五年的C语言笔记!你现在知道别人为什么这么优秀了吗?

c语言对许多同学来说确实是一门比较难学的课程&#xff0c;不仅抽象&#xff0c;而且繁琐&#xff0c;但这又是一门不得不学的课程。前两节可能还有兴致听一听&#xff0c;然而&#xff0c;再过几节课就是一脸蒙比。凭空要想出一道题的算法和程序&#xff0c;根本无从下手。 所…

C语言/C++编程学习:C语言环境设置!

C语言是面向过程的&#xff0c;而C&#xff0b;&#xff0b;是面向对象的 C和C的区别&#xff1a; C是一个结构化语言&#xff0c;它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程&#xff0c;对输入&#xff08;或环境条件&#xff09;进行运算处理得…

C语言指针原来也可以这么的通俗易懂!

C语言是面向过程的&#xff0c;而C&#xff0b;&#xff0b;是面向对象的 C和C的区别&#xff1a; C是一个结构化语言&#xff0c;它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程&#xff0c;对输入&#xff08;或环境条件&#xff09;进行运算处理得…

C语言过时了?你在做梦?

为什么要使用C语言&#xff1f; 在过去的四十年里&#xff0c;C语言已经成为世界上最流行、最重要的一种编程语言。 C是一种融合了控制特性的现代语言&#xff0c;而我们已发现在计算机科学的理论和实践中&#xff0c;控制特性是很重要的。其设计使得用户可以自然地采用自顶向…

C语言深入理解!助你向大佬迈进!

Dennis Ritchie 过世了&#xff0c;他发明了C语言&#xff0c;一个影响深远并彻底改变世界的计算机语言。一门经历40多年的到今天还长盛不衰的语言&#xff0c;今天很多语言都受到C的影响&#xff0c;C&#xff0c;Java&#xff0c;C#&#xff0c;Perl&#xff0c; PHP&#xf…

【初涉C语言】程序员欢迎来到C语言的世界!

计算机发展史 机器语言所有的代码里面只有0和1优点&#xff1a;直接对硬件产生作用&#xff0c;程序的执行效率非常高缺点&#xff1a;指令又多又难记、可读性差、无可移植性汇编语言符号化的机器语言&#xff0c;用一个符号&#xff08;英文单词、数字&#xff09;来代表一条…

C语言和C++的区别整理详解!

c和c主要区别 根据书中的描述&#xff0c;进行了整理 推荐一个我自己的C/C交流裙815393895 1、 源代码文件的扩展名 摘自1.4.1 C实现源代码文件的扩展名UNIXC、cc、cxx、cGNU CC、cc、cxx、cpp、cDigital Marscpp、cxxBorland CcppWatcomcppMicrosoft Visual Ccpp、cxx、cc…

揭示C语言函数调用的本质解析

C语言是面向过程的&#xff0c;而C&#xff0b;&#xff0b;是面向对象的C和C的区别&#xff1a; C是一个结构化语言&#xff0c;它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程&#xff0c;对输入&#xff08;或环境条件&#xff09;进行运算处理得到…

C语言/C++编程学习:不找C/C++的工作也要学C/C++的原因

C语言是面向过程的&#xff0c;而C&#xff0b;&#xff0b;是面向对象的 C和C的区别&#xff1a; C是一个结构化语言&#xff0c;它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程&#xff0c;对输入&#xff08;或环境条件&#xff09;进行运算处理得…

【网络攻防】精通C语言的黑客才是真正的黑客!

精通C语言的黑客才是真正的黑客 黑客界&#xff0c;有两样重要的课程&#xff0c;一是计算机的本质&#xff0c;二是编译原理。相对于汇编等底层语言&#xff0c;它简单&#xff1b;相对于其它高级语言&#xff0c;它更为接近计算机&#xff1b;同样它对黑客的两大课程很有帮助…

我两小时学完指针,你学会数组/指针与函数需要多久?

数组与函数&#xff1a; 这段函数中 函数的参数是数组&#xff0c;注意数组作为函数参数时&#xff0c;数组名和数组元素个数时分别传递的。 指针与函数&#xff1a; 这段函数中的参数是指针变量&#xff0c;传入的是数组的数组名或者首元素的地址&#xff0c;然后用引领操作…