当前位置: 首页 > backend >正文

@EnableAsync+@Async源码学习笔记之四

接上一篇,我们进入 AsyncAnnotationAdvisor 的分析,源码如下:

package org.springframework.scheduling.annotation;import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.Executor;import org.aopalliance.aop.Advice;import org.springframework.aop.Pointcut;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;/*** Advisor that activates asynchronous method execution through the {@link Async}* annotation. This annotation can be used at the method and type level in* implementation classes as well as in service interfaces.** <p>This advisor detects the EJB 3.1 {@code javax.ejb.Asynchronous}* annotation as well, treating it exactly like Spring's own {@code Async}.* Furthermore, a custom async annotation type may get specified through the* {@link #setAsyncAnnotationType "asyncAnnotationType"} property.** @author Juergen Hoeller* @since 3.0* @see Async* @see AnnotationAsyncExecutionInterceptor*/
@SuppressWarnings("serial")
public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {private AsyncUncaughtExceptionHandler exceptionHandler;private Advice advice;private Pointcut pointcut;/*** Create a new {@code AsyncAnnotationAdvisor} for bean-style configuration.*/public AsyncAnnotationAdvisor() {this(null, null);}/*** Create a new {@code AsyncAnnotationAdvisor} for the given task executor.* @param executor the task executor to use for asynchronous methods* (can be {@code null} to trigger default executor resolution)* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use to* handle unexpected exception thrown by asynchronous method executions* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)*/@SuppressWarnings("unchecked")public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);System.out.println("默认支持spring的Async注解和EJB的javax.ejb.Asynchronous");asyncAnnotationTypes.add(Async.class);try {asyncAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));}catch (ClassNotFoundException ex) {// If EJB 3.1 API not present, simply ignore.}if (exceptionHandler != null) {this.exceptionHandler = exceptionHandler;}else {System.out.println("如果没有指定异常处理器的话,则用默认的异常处理器 SimpleAsyncUncaughtExceptionHandler  ");System.out.println("默认的异常处理器 SimpleAsyncUncaughtExceptionHandler 所做的事情就是把异常打印到日志里边 ");this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();}// 构造通知和切点this.advice = buildAdvice(executor, this.exceptionHandler);this.pointcut = buildPointcut(asyncAnnotationTypes);}/*** Specify the default task executor to use for asynchronous methods.*/public void setTaskExecutor(Executor executor) {this.advice = buildAdvice(executor, this.exceptionHandler);}/*** Set the 'async' annotation type.* <p>The default async annotation type is the {@link Async} annotation, as well* as the EJB 3.1 {@code javax.ejb.Asynchronous} annotation (if present).* <p>This setter property exists so that developers can provide their own* (non-Spring-specific) annotation type to indicate that a method is to* be executed asynchronously.* @param asyncAnnotationType the desired annotation type*/public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) {Assert.notNull(asyncAnnotationType, "'asyncAnnotationType' must not be null");Set<Class<? extends Annotation>> asyncAnnotationTypes = new HashSet<>();asyncAnnotationTypes.add(asyncAnnotationType);this.pointcut = buildPointcut(asyncAnnotationTypes);}/*** Set the {@code BeanFactory} to be used when looking up executors by qualifier.*/@Overridepublic void setBeanFactory(BeanFactory beanFactory) {if (this.advice instanceof BeanFactoryAware) {((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);}}@Overridepublic Advice getAdvice() {return this.advice;}@Overridepublic Pointcut getPointcut() {return this.pointcut;}protected Advice buildAdvice(@Nullable Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);}/*** Calculate a pointcut for the given async annotation types, if any.* @param asyncAnnotationTypes the async annotation types to introspect* @return the applicable Pointcut object, or {@code null} if none*/protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {ComposablePointcut result = null;for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);if (result == null) {result = new ComposablePointcut(cpc);}else {result.union(cpc);}result = result.union(mpc);}return (result != null ? result : Pointcut.TRUE);}
}
  • 首先要关注的就是有2个参数的构造方法,也是上一篇文章最后提到的,有疑问可以看上一篇,调用的地方如下:
// 重点就是这个 AsyncAnnotationAdvisor
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);

这个构造方法,第一步,用一个 Set 来存储 spring 的 @Async 注解和 EJB 的 @javax.ejb.Asynchronous 注解

Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
System.out.println("默认支持spring的Async注解和EJB的javax.ejb.Asynchronous");
asyncAnnotationTypes.add(Async.class);
try {asyncAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {// If EJB 3.1 API not present, simply ignore.
}

构造方法的第二步,是对异常处理器的处理,代码如下:

if (exceptionHandler != null) {this.exceptionHandler = exceptionHandler;
}
else {System.out.println("如果没有指定异常处理器的话,则用默认的异常处理器 SimpleAsyncUncaughtExceptionHandler  ");System.out.println("默认的异常处理器 SimpleAsyncUncaughtExceptionHandler 所做的事情就是把异常打印到日志里边 ");this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
}

如果入参给了异常处理器,就将入参的异常处理器赋值给成员变量,否则就用默认的SimpleAsyncUncaughtExceptionHandler
构造方法的第三步,构造通知和切点,代码如下:

this.advice = buildAdvice(executor, this.exceptionHandler);
this.pointcut = buildPointcut(asyncAnnotationTypes);

先看构造通知:

protected Advice buildAdvice(@Nullable Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);
}

其实就是new了一个拦截器AnnotationAsyncExecutionInterceptor
再看构造切点:

protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {ComposablePointcut result = null;for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);if (result == null) {result = new ComposablePointcut(cpc);}else {result.union(cpc);}result = result.union(mpc);}return (result != null ? result : Pointcut.TRUE);
}

这里边其实就是定位标记有 @Async@javax.ejb.Asynchronous 的方法,也就是你写的异步方法,当然,不仅仅是这2个注解,还有你自定义的注解。
到这里有人可能会疑惑,我从构造方法一路追过来,入参中的 asyncAnnotationTypes 里边就俩值 @Async@javax.ejb.Asynchronous 啊。
哪里还有我自定义的注解,不要着急,这个 buildPointcut 方法在 setAsyncAnnotationType 方法中被调用了一次,就是在那一次中,传入了你自定义的注解。
setAsyncAnnotationType 是在上文中讲的 AsyncAnnotationBeanPostProcessorsetBeanFactory 方法中被调用的,再看下:

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

下面这几行代码,就解析了 @Async@javax.ejb.Asynchronous 以及你自定义的异步注解。
第一行解析了 @Async@javax.ejb.Asynchronous
第三行解析了你自定义的注解。

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

最后,总结下:本文讲了两个重点,一个是构造切点,一个是构造通知。构造切点,我们讲的比较细致了。构造切面,也就是拦截器 AnnotationAsyncExecutionInterceptor 我们下一篇讲。

http://www.xdnf.cn/news/575.html

相关文章:

  • 2025年第十五届MathorCup数学应用挑战赛D题论文全网首发
  • MSCKF——运动方程IMU状态递推(Propagation)
  • 深度补全网络:CSPN++ 有哪些开源项目
  • 2025华中杯挑战赛B题【单车调度】原创论文讲解
  • docker 搭建nacos 2.2.1版本单机版
  • 国产SMT贴片机自主技术突破解析
  • A股周度复盘与下周策略 的deepseek提示词模板
  • Unreal 从入门到精通之如何接入MQTT
  • 【开发心得】Dify部署ollama模型的坑[8]
  • 【漫话机器学习系列】210.标准化(Standardization)
  • [Java · 初窥门径] Java 注释符
  • DEV-c++怎么免打头文件中英文切换
  • c语言中的原,反,补码
  • PyTorch 深度学习实战(38):注意力机制全面解析(从Seq2Seq到Transformer)
  • “劣币驱逐良币”与“U型锁”刍议
  • Linux中的软件管理
  • 解决Windows update服务启动拒绝访问的问题 | wuauserv 注册表拒绝访问的方法
  • Sleuth+Zipkin 服务链路追踪
  • 四级英语备考指南
  • 信息量、香农熵、交叉熵、KL散度总结
  • PowerBi中DATEDIFF怎么使用?
  • vue3 中 iframe 多页面切换导致资源刷新的问题解决
  • 从句详细解析
  • 群晖威联通飞牛等nas如何把宿主机硬盘挂接到可道云docker容器中
  • 【Envi遥感图像处理】016:如何下载NOAA AVHRR GIMMS 全球数据集?
  • 结构体详解
  • (10)VTK C++开发示例 --- 点和线之间的距离
  • 【入门】数字之和为13的整数
  • Doris,新一代实时数仓核心基础设施
  • 数据防泄漏:企业信息安全的重要防线