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 { .... @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异步调用原理及SpringAop拦截器链都已经分析完毕,希望对大家使用spring异步调用有所帮助。另外我自己也重新温习了spring aop相关的知识,也希望大家对spring aop有一个新的认识。如果有需要源码的同学,请f访问我的github:Spring异步调用原理及实现方案demo。
Spring异步调用原理及SpringAop拦截器链原理的更多相关文章
- spring---aop(3)---Spring AOP的拦截器链
写在前面 时间断断续续,这次写一点关于spring aop拦截器链的记载.至于如何获取spring的拦截器,前一篇博客已经写的很清楚(spring---aop(2)---Spring AOP的JDK动 ...
- 浅谈Struts2拦截器的原理与实现
拦截器与过滤器 拦截器是对调用的Action起作用,它提供了一种机制可以使开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了 ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- 自己打断点走的struts流程&拦截器工作原理
①. 请求发送给 StrutsPrepareAndExecuteFilter ②. StrutsPrepareAndExecuteFilter 判定该请求是否是一个 Struts2 请 求(Actio ...
- Mybatis拦截器实现原理深度分析
1.拦截器简介 拦截器可以说使我们平时开发经常用到的技术了,Spring AOP.Mybatis自定义插件原理都是基于拦截器实现的,而拦截器又是以动态代理为基础实现的,每个框架对拦截器的实现不完全相同 ...
- 【SSM】拦截器的原理、实现
一.背景: 走过了双11,我们又迎来了黑色星期五,刚过了黑五,双12又将到来.不管剁手的没有剁手的,估计这次都要剁手了!虽然作为程序猿的我,没有钱但是我们长眼睛了,我们关注到的是我们天猫.淘宝.支付宝 ...
- Struts自定义拦截器&拦截器工作原理
0.拦截器的调用原理: 拦截器是一个继承了序列化接口的普通接口.其工作原理是讲需要被拦截的对象作为参数传到intercept()方法内,在方法内部对此对象进行处理之后再执行原方法.intercept( ...
- SpringMVC 拦截器实现原理和登录实现
SpringMVC 拦截器的原理图 springMVC拦截器的实现一般有两种方式 第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口 第二种方 ...
- 【ssm】拦截器的原理及实现
一.背景: 走过了双11,我们又迎来了黑色星期五,刚过了黑五,双12又将到来.不管剁手的没有剁手的,估计这次都要剁手了!虽然作为程序猿的我,没有钱但是我们长眼睛了,我们关注到的是我们天猫.淘宝.支付宝 ...
随机推荐
- python实现域名解析和归属地查询
前言工作中有时要查询域名解析和获取域名相关IP归属地信息 安装依赖python2:pip install dnspythonpython3:python3 -m pip install -i http ...
- Java之函数式接口
函数式接口 概述:接口中只有一个抽象方法 下面介绍的可能很抽象,理解不了,至少在我看来单独的这几个借口是没有用的,跟最下面说的 Stream流一起用才会有效果 函数式接口,即适用于函数式编程场景的接口 ...
- 用IntelliJ IDEA 开发Spring+SpringMVC+Mybatis框架 分步搭建一:建立MAVEN Web项目
一:创建maven web项目er
- [拓展Bsgs] Clever - Y
题目链接 Clever - Y 题意 有同余方程 \(X^Y \equiv K\ (mod\ Z)\),给定\(X\),\(Z\),\(K\),求\(Y\). 解法 如题,是拓展 \(Bsgs\) 板 ...
- xshell连接ubuntu系统
1.登录虚拟机 2.关闭本机所有防火墙和杀毒软件 sudo ufw status 查看防火墙状态 sudo ufw disable 关闭防火墙 sudo ufw enable 打开防火墙 3.安装ss ...
- Hadoop启动脚本分析
Hadoop启动脚本分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 能看到这篇博客的你估计对Hadoop已经有一个系统的了解了,最起码各种搭建方式你应该是会的,不会也没有关系, ...
- 069、Calico的默认连通性(2019-04-12 周五)
参考https://www.cnblogs.com/CloudMan6/p/7536746.html Calico 跨主机连通性测试 root@host1:~# docker exec bbo ...
- [物理学与PDEs]第4章习题4 一维理想反应流体力学方程组的守恒律形式及其 R.H. 条件
写出在忽略粘性与热传导性, 即设 $\mu=\mu'=\kappa=0$ 的情况, 在 Euler 坐标系下具守恒律形式的一维反应流动力学方程组. 由此求出在解的强间断线上应满足的 R.H. 条件 ( ...
- PHP微信公众号JSAPI网页支付(下)
上一篇PHP微信公众号JSAPI网页支付(上)中讲到了公众号平台的相关设置以及支付的大致流程. 这一篇重点讲支付后,异步接受回调通知,以及处理后同步通知微信服务器. 首先梳理下整个jsapi支付的流程 ...
- Beta 冲刺(3/7)
目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(3/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 整理博客 ppt模板 接下来的计划 做好机动. ...