javascript
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 — 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。
//如果是advisedif (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
總結
以上是生活随笔為你收集整理的Spring异步调用原理及SpringAop拦截器链原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SSM(Spring+Spring MV
- 下一篇: 本田泰国弯刀150冷车难启动是什么原因?