本系列文章简介:
在现代的开发中,异步编程已经成为了必备的技能。随着计算机性能的提升和多核处理器的普及,异步编程可以充分利用系统资源,提高程序的性能和响应速度。在Spring Boot项目中,异步编程也得到了广泛的应用。
异步编程可以让我们在执行耗时操作时,不需要等待其完成,而是直接返回结果,然后在合适的时候再处理这个结果。这样可以提高程序的并发性能,提升用户体验。
Spring Boot提供了很多异步编程的支持,包括使用注解方式、使用线程池、使用消息队列等等。底层实现原理主要是通过线程池来实现的。
在使用异步编程时,我们需要注意一些使用方式。首先,要明确哪些操作是可以异步执行的,比如数据库访问、网络请求等。其次,要合理配置线程池的大小和其他参数,避免出现线程池资源耗尽的情况。此外,还需要考虑异步操作的异常处理和结果回调等问题。
在本系列文章中,我们将介绍Spring Boot异步编程的底层实现原理,并给出一些正确的使用方式和注意事项。通过学习和掌握异步编程的知识,我们可以更好地利用系统资源,提高程序的性能和效率。让我们一起来探索异步编程的奥秘吧!
欢迎大家订阅《Java技术栈高级攻略》专栏,一起学习,一起涨分!
目录
1、前言
2、Springboot项目之基于@Async实现异步编码
2.1 开启异步注解
2.2 异步调用底层实现原理
2.2.1 @EnableAsync
2.2.2 @Async
2.3 异步线程池如何选择
3、结语
1、前言
在现代软件开发中,异步编程已经变得越来越重要。随着计算机性能的提升和用户对高效响应的需求,异步编程可以提供更好的用户体验和更高的系统性能。
异步编程的原理是将耗时的操作放在后台线程中执行,不阻塞主线程的执行。这样可以使程序能够同时处理多个任务,并在任务完成后立即响应用户,提高程序的并发能力和响应速度。
本文将跟随《Springboot项目中,异步编程底层实现原理详解(一)》的进度,继续介绍异步编程。希望通过本系列文章的学习,您将能够更好地理解异步编程的内部工作原理,掌握异步编程的使用技巧,以及通过合理的设计完成最佳实践,充分发挥优化异步编程的潜力,为系统的高效运行提供有力保障。
2、Springboot项目之基于@Async实现异步编码
2.1 开启异步注解
详见 《Springboot项目中,异步编程底层实现原理详解(一)》
2.2 异步调用底层实现原理
想要深入理解底层实现原理,无非从两个注解入手,@EnableAsync和@Async,接下来,带大家一起从头撸一遍底层源码,看看这两个神兽到底是如何让各路妖魔闻风丧胆。
2.2.1 @EnableAsync
我们先来看一下@EnableAsync注解的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {/*** 自定义异步注解,@Async和@javax.ejb.Asynchronous默认是会被检测到的*/Class<? extends Annotation> annotation() default Annotation.class;/*** 使用子类代理(CGLIB)还是基于接口的代理(JDK代理)*/boolean proxyTargetClass() default false;/*** 使用哪种advice,PROXY是基于代理的,另外一种是切面织入形式的*/AdviceMode mode() default AdviceMode.PROXY;/*** 表明AsyncAnnotationBeanPostProcessor这个后置处理器的应用顺序*/int order() default Ordered.LOWEST_PRECEDENCE;
}
重点关注以下@Import注解,该注解注入了AsyncConfigurationSelector类,继承自AdviceModeImportSelector类,后者实现了ImportSelector接口。
关系结构图如下:
他们内部具体经历了怎么的化学反应?咱们接着往下看👇👇👇
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME ="org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";@Override@Nullablepublic 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;}}}
AsyncConfigurationSelector 类中重写了父类AdviceModeImportSelector中的selectImports方法,该方法会根据EnableAsync 接口中传递的adviceMode值,返回不同的字符串数组,每个数组中的元素为一个需要导入的配置类名。换言之,这个方法就是一个选择器,根据不同的代理模式,加载不同的配置类。
下面我们先分析一下PROXY模式的ProxyAsyncConfiguration配置类,源码如下:
@Configuration(proxyBeanMethods = false)
@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");//初始化Bean对象AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();//设置执行器和异常处理器bpp.configure(this.executor, this.exceptionHandler);Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");//设置annotationif (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配置类继承了AbstractAsyncConfiguration类,这个类用于配置异步任务的线程池与执行器。它提供了一些默认实现,使配置变得更加简单和快捷,并且更加易于扩展。
在这个ProxyAsyncConfiguration配置类中,初始化了一个AsyncAnnotationBeanPostProcessor对象,AsyncAnnotationBeanPostProcessor是Spring框架中的一个异步注解后置处理器,用于处理带有@Async注解的方法。它的主要作用是将这些方法转换为异步执行的任务,并使用适当的线程池进行调度和管理。
所以在这个配置类中,主要的作用就是在asyncAdvisor方法中定义了一个Bean异步注解后置处理器,负责解析带@Async注解的方法,并将其包装成一个异步任务。
异步任务封装的具体逻辑,暂且不谈,放在后边再讲。回过头来看一下这个类AsyncConfigurationSelector实例化的时机,以及做了哪些具体的操作。下面看下这段代码:
AsyncConfigurationSelector是在ConfigurationClassParser的processImports方法中,进行实例化的,而获取所有Import是通过ConfigurationClassParser的Set getImports(SourceClass sourceClass)方法,从启动类注解开始,递归遍历所有注解上的@Import注解,获取@Import注解的value值。ConfigurationClassParser的processImports方法循环遍历所有Import的value值,对每一个实例化的selector,实例化每个selector后,会继续调用每个selector的selectImports(adviceMode)方法,获取到每个selector配置的imports配置类,对这些配置类继续递归调用ConfigurationClassParser的processImports方法实例化每个import配置类。这样就实现了@Import注解的功能,根据配置导入相应的配置类。
看到这里,估计要死好多脑细胞啦。。。。没办法啊,谁叫人家底层实现设计的如此完美。脑回路早已深陷其中,无法自拔,哈哈哈。。。
拧开早已泡好的枸杞红茶,咕嘟咕嘟喝几口,继续研究前文中所提到的异步方法的封装。研究这个内容之前,就要分析下面三个类: AbstractAdvisingBeanPostProcessor、AbstractBeanFactoryAwareAdvisingPostProcessor、AsyncAnnotationBeanPostProcessor。
关系结构图如下:
AbstractAdvisingBeanPostProcessor源码如下:
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {@Nullableprotected Advisor advisor;protected boolean beforeExistingAdvisors = false;private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<>(256);public void setBeforeExistingAdvisors(boolean beforeExistingAdvisors) {this.beforeExistingAdvisors = beforeExistingAdvisors;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}@Overridepublic 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);// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader = getProxyClassLoader();if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();}return proxyFactory.getProxy(classLoader);}// No proxy needed.return bean;}protected boolean isEligible(Object bean, String beanName) {return isEligible(bean.getClass());}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;}protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);proxyFactory.setTarget(bean);return proxyFactory;}protected void customizeProxyFactory(ProxyFactory proxyFactory) {}}
AbstractAdvisingBeanPostProcessor类是Spring框架中的一个后置处理器(BeanPostProcessor),它的作用是为Spring容器中的Bean对象配置Advisor(通知者),以实现特定的切面功能。
具体来说,当Spring容器中的Bean对象符合特定的条件时(例如,实现了AOP接口),AbstractAdvisingBeanPostProcessor会自动为这些对象创建代理对象,并将Advisor(通知者)织入到代理对象的方法执行流程中,实现对目标方法的拦截、增强等功能。这样就可以通过配置Advisor来实现AOP编程中的切面功能,例如:事务管理、日志记录、权限控制等。
AbstractAdvisingBeanPostProcessor类是Spring框架中的一个重要组件,为实现Spring AOP提供了关键的支持。
AbstractBeanFactoryAwareAdvisingPostProcessor源码如下:
public abstract class AbstractBeanFactoryAwareAdvisingPostProcessor extends AbstractAdvisingBeanPostProcessorimplements BeanFactoryAware {@Nullableprivate ConfigurableListableBeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory ?(ConfigurableListableBeanFactory) beanFactory : null);}@Overrideprotected 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;}@Overrideprotected boolean isEligible(Object bean, String beanName) {return (!AutoProxyUtils.isOriginalInstance(beanName, bean.getClass()) &&super.isEligible(bean, beanName));}}
AbstractBeanFactoryAwareAdvisingPostProcessor类是Spring AOP中的一个处理器(post-processor),用于向BeanFactory中注入Advisor和Advice以完成AOP的配置和管理。该类实现了BeanFactoryAware和BeanPostProcessor接口,能够获取BeanFactory的实例,并在Bean初始化之后对Bean进行代理。
具体来说,AbstractBeanFactoryAwareAdvisingPostProcessor会在Spring容器创建Bean实例并完成依赖注入后,在Bean初始化之前,通过BeanFactory获取所有Advisor,并对当前Bean进行匹配。如果当前Bean所属的类或实现了指定的接口,则将对应的Advisor和Advice应用于该Bean,生成代理对象。代理对象可以拦截方法调用并执行Advice中的逻辑。
通过AbstractBeanFactoryAwareAdvisingPostProcessor,我们可以方便地为一组Bean配置共享的Advisor和Advice,从而实现统一的AOP逻辑。这在很多场景下非常有用,例如日志、事务、性能监控等。
AsyncAnnotationBeanPostProcessor源码如下:
public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME =AnnotationAsyncExecutionInterceptor.DEFAULT_TASK_EXECUTOR_BEAN_NAME;protected final Log logger = LogFactory.getLog(getClass());@Nullableprivate Supplier<Executor> executor;@Nullableprivate Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;@Nullableprivate Class<? extends Annotation> asyncAnnotationType;public AsyncAnnotationBeanPostProcessor() {setBeforeExistingAdvisors(true);}public void configure(@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {this.executor = executor;this.exceptionHandler = exceptionHandler;}public void setExecutor(Executor executor) {this.executor = SingletonSupplier.of(executor);}public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {this.exceptionHandler = SingletonSupplier.of(exceptionHandler);}public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) {Assert.notNull(asyncAnnotationType, "'asyncAnnotationType' must not be null");this.asyncAnnotationType = asyncAnnotationType;}@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;}}
AsyncAnnotationBeanPostProcessor类是Spring框架中的一个后置处理器(BeanPostProcessor),主要作用是将使用@Async注解的方法进行异步化处理。通过该后置处理器,Spring框架会为在Bean中使用@Async注解的方法创建一个代理对象,并将该代理对象注入到容器中,以便能够异步执行该方法,从而避免阻塞主线程。
具体来说,AsyncAnnotationBeanPostProcessor类会:
-
扫描容器中所有的Bean,找到使用了@Async注解的方法;
-
为这些方法创建一个代理对象;
-
将代理对象注入到容器中;
-
当调用被代理的方法时,会先将该方法封装成一个Runnable对象,并交给一个Executor去执行。在执行的过程中,原来的线程可以继续执行其他操作。
总之,AsyncAnnotationBeanPostProcessor类可以帮助我们在Spring框架中方便地实现异步化操作,提高系统的性能和并发能力。
接下来,还需要研究AsyncAnnotationAdvisor这个对象,了解一下它的实例化的时机,以及如何拦截异步方法,如何实现异步调用逻辑。
AsyncAnnotationAdvisor类结构如下:
AsyncAnnotationAdvisor源码如下:
public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {private Advice advice;private Pointcut pointcut;public AsyncAnnotationAdvisor() {this((Supplier<Executor>) null, (Supplier<AsyncUncaughtExceptionHandler>) null);}public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {this(SingletonSupplier.ofNullable(executor), SingletonSupplier.ofNullable(exceptionHandler));}@SuppressWarnings("unchecked")public AsyncAnnotationAdvisor(@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);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.}this.advice = buildAdvice(executor, exceptionHandler);this.pointcut = buildPointcut(asyncAnnotationTypes);}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);}@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 Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);interceptor.configure(executor, exceptionHandler);return interceptor;}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);}}
最后还要研究下两个类:AnnotationAsyncExecutionInterceptor、AnnotationMatchingPointcut两个类、整个异步处理流程就全部结束了。
AnnotationAsyncExecutionInterceptor类结构如下:
AnnotationAsyncExecutionInterceptor源码如下:
public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionInterceptor {public AnnotationAsyncExecutionInterceptor(@Nullable Executor defaultExecutor) {super(defaultExecutor);}public AnnotationAsyncExecutionInterceptor(@Nullable Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) {super(defaultExecutor, exceptionHandler);}@Override@Nullableprotected String getExecutorQualifier(Method method) {// Maintainer's note: changes made here should also be made in// AnnotationAsyncExecutionAspect#getExecutorQualifierAsync async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);if (async == null) {async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);}return (async != null ? async.value() : null);}}
AnnotationAsyncExecutionInterceptor类是一个拦截器,用于处理异步方法的执行。它主要的作用是:
- 拦截异步方法的执行,以便进行处理和控制异步流程;
- 将异步方法包装成一个Future对象,以便获取异步执行结果;
- 处理异步方法的异常,将异常信息包装成一个ExecutionException对象,以便在获取异步执行结果时能够捕获异常。
AnnotationAsyncExecutionInterceptor类通常用于Spring框架中的异步方法执行,它实现了MethodInterceptor接口,并且使用了@Async注解来标识异步方法。当Spring容器执行带有@Async注解的方法时,AnnotationAsyncExecutionInterceptor会拦截这个方法的执行,并进行异步处理。
AnnotationMatchingPointcut源码如下:
public class AnnotationMatchingPointcut implements Pointcut {private final ClassFilter classFilter;private final MethodMatcher methodMatcher;public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType) {this(classAnnotationType, false);}public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited) {this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);this.methodMatcher = MethodMatcher.TRUE;}public AnnotationMatchingPointcut(@Nullable Class<? extends Annotation> classAnnotationType,@Nullable Class<? extends Annotation> methodAnnotationType) {this(classAnnotationType, methodAnnotationType, false);}public AnnotationMatchingPointcut(@Nullable Class<? extends Annotation> classAnnotationType,@Nullable Class<? extends Annotation> methodAnnotationType, boolean checkInherited) {Assert.isTrue((classAnnotationType != null || methodAnnotationType != null),"Either Class annotation type or Method annotation type needs to be specified (or both)");if (classAnnotationType != null) {this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);}else {this.classFilter = new AnnotationCandidateClassFilter(methodAnnotationType);}if (methodAnnotationType != null) {this.methodMatcher = new AnnotationMethodMatcher(methodAnnotationType, checkInherited);}else {this.methodMatcher = MethodMatcher.TRUE;}}@Overridepublic ClassFilter getClassFilter() {return this.classFilter;}@Overridepublic MethodMatcher getMethodMatcher() {return this.methodMatcher;}@Overridepublic boolean equals(@Nullable Object other) {if (this == other) {return true;}if (!(other instanceof AnnotationMatchingPointcut)) {return false;}AnnotationMatchingPointcut otherPointcut = (AnnotationMatchingPointcut) other;return (this.classFilter.equals(otherPointcut.classFilter) &&this.methodMatcher.equals(otherPointcut.methodMatcher));}@Overridepublic int hashCode() {return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode();}@Overridepublic String toString() {return "AnnotationMatchingPointcut: " + this.classFilter + ", " + this.methodMatcher;}public static AnnotationMatchingPointcut forClassAnnotation(Class<? extends Annotation> annotationType) {Assert.notNull(annotationType, "Annotation type must not be null");return new AnnotationMatchingPointcut(annotationType);}public static AnnotationMatchingPointcut forMethodAnnotation(Class<? extends Annotation> annotationType) {Assert.notNull(annotationType, "Annotation type must not be null");return new AnnotationMatchingPointcut(null, annotationType);}private static class AnnotationCandidateClassFilter implements ClassFilter {private final Class<? extends Annotation> annotationType;AnnotationCandidateClassFilter(Class<? extends Annotation> annotationType) {this.annotationType = annotationType;}@Overridepublic boolean matches(Class<?> clazz) {return AnnotationUtils.isCandidateClass(clazz, this.annotationType);}@Overridepublic boolean equals(Object obj) {if (this == obj) {return true;}if (!(obj instanceof AnnotationCandidateClassFilter)) {return false;}AnnotationCandidateClassFilter that = (AnnotationCandidateClassFilter) obj;return this.annotationType.equals(that.annotationType);}@Overridepublic int hashCode() {return this.annotationType.hashCode();}@Overridepublic String toString() {return getClass().getName() + ": " + this.annotationType;}}}
AnnotationMatchingPointcut类是Spring AOP框架中的一个切点实现类,用于匹配被特定注解标记的方法、类或字段。
在使用AOP时,我们需要通过切点指定哪些类、方法需要被拦截。AnnotationMatchingPointcut就可以根据指定的注解类型来匹配需要被拦截的类、方法或字段。
在AsyncAnnotationAdvisor类中的Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes)这个方法,我们传进来了@Async和@javax.ejb.Asynchronous注解,对每个注解,在类和方法级别都创建了AnnotationMatchingPointcut对象,并通过ComposablePointcut对象把所有的切点组合在一起。
看到这里,大家估计都有点懵了吧,源码的逻辑比较复杂,这部分的内容就不再进行深入研究。。。。。。。。。。。。。。总结一下:
在项目启动阶段,通过@EnableAsync注解导入一些配置类,最终实例化一个异步注解的后置处理器(AsyncAnnotationBeanPostProcessor),这个后置处理器有自己的切入点和处理逻辑,会拦截项目中所有的bean,如果某个bean符合该后置处理器的切入点,那么SpringBoot会通过AOP生成一个代理对象,生成代理对象时会设置一个回调,回调的内容就是后置处理器中的处理逻辑(实际逻辑就是将异步方法内容放入线程池中执行),并将这个代理对象注入到使用的地方。
当真正调用异步方法时,因为注入的是代理对象,那么调用到异步方法之前会进入之前设置的回调,去执行异步方法内容,执行完毕后会根据不同的返回值类型处理返回值,至此异步方法就执行完毕。
回过头来看下 @Async注解👇👇👇
2.2.2 @Async
@Async是Spring框架中的一个注解,用于表示被注解的方法是一个异步方法。在使用@Async
注解后,方式会在调用时立即返回一个Future
对象,方法的执行则会在新的线程中异步进行。
@Async注解源码如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {String value() default "";}
Async对象中,只有一个value属性,可以指定异步线程池的名称,默认空。在项目使用过程中,避免使用默认线程池,需要自定义线程池,究其原因,且往下继续看👇👇👇
2.3 异步线程池如何选择
详见《Springboot项目中,异步编程底层实现原理详解(三)》
3、结语
文章至此,已接近尾声!希望此文能够对大家有所启发和帮助。同时,感谢大家的耐心阅读和对本文档的信任。在未来的技术学习和工作中,期待与各位大佬共同进步,共同探索新的技术前沿。最后,再次感谢各位的支持和关注。您的支持是作者创作的最大动力,如果您觉得这篇文章对您有所帮助,请分享给身边的朋友和同事!