Springboot项目中,异步编程底层实现原理详解(二)

本系列文章简介:

        在现代的开发中,异步编程已经成为了必备的技能。随着计算机性能的提升和多核处理器的普及,异步编程可以充分利用系统资源,提高程序的性能和响应速度。在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类会:

  1. 扫描容器中所有的Bean,找到使用了@Async注解的方法;

  2. 为这些方法创建一个代理对象;

  3. 将代理对象注入到容器中;

  4. 当调用被代理的方法时,会先将该方法封装成一个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类是一个拦截器,用于处理异步方法的执行。它主要的作用是:

  1. 拦截异步方法的执行,以便进行处理和控制异步流程;
  2. 将异步方法包装成一个Future对象,以便获取异步执行结果;
  3. 处理异步方法的异常,将异常信息包装成一个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、结语

 文章至此,已接近尾声!希望此文能够对大家有所启发和帮助。同时,感谢大家的耐心阅读和对本文档的信任。在未来的技术学习和工作中,期待与各位大佬共同进步,共同探索新的技术前沿。最后,再次感谢各位的支持和关注。您的支持是作者创作的最大动力,如果您觉得这篇文章对您有所帮助,请分享给身边的朋友和同事!

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

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

相关文章

短视频流媒体平台的系统设计

1. 功能需求: 我们的系统有两类参与者 内容创作者 •上传任何类型的视频&#xff08;格式编解码器&#xff09;•视频可以被删除•视频元数据•必填项: 标题&#xff0c;作者&#xff0c;描述•选填项: 分类/标签列表•可以随时更新•当视频对观众可用时&#xff0c;向内容创作…

力扣110. 平衡二叉树

思路&#xff1a;与二叉树最大高度类似&#xff0c;但是这里需要返回 -1 的高度来标识不是平衡二叉树&#xff0c;判断左右子树的高度相差大于1则不平衡&#xff0c;否则就是平衡。 class Solution {public boolean isBalanced(TreeNode root) {int ans func(root);if(ans >…

【人工智能基础】状态空间搜索

状态空间法 状态空间&#xff1a;一个问题全部可能的状态以及其关系的集合。 状态空间图&#xff1a;以图的形式表示问题的状态空间&#xff0c;节点对应状态&#xff0c;边对应状态转移算子&#xff0c;边上的权对应转移所需的代价 问题的解&#xff1a;是从最开始状态到目…

聊聊路径规划算法(二)——图搜索法

图搜索法通过利用已有的环境地图和版图中的障碍物等数据信息建立&#xff0c;由起点至结束点的可行路线。一般分为深度最优和广度最优二种走向。深度优先算法优先拓展搜索深度较大的节点&#xff0c;因此能够更迅速的获得下一个可行路径&#xff0c;不过深度优先算法获取的第一…

Adobe Firefly是否将重新定义AI视频编辑领域?|TodayAI

Adobe最近发布了一段令人瞩目的视频&#xff0c;详细展示了其最新推出的Adobe Firefly视频模型。这一模型集成了尖端的生成式人工智能技术&#xff0c;带来了一系列颠覆性的视频编辑功能&#xff0c;引发了业界的广泛关注和讨论。 视频中的旁白充满热情地宣布&#xff1a;“Ad…

Rabbit加密算法:性能与安全的完美结合

title: Rabbit加密算法&#xff1a;性能与安全的完美结合 date: 2024/4/19 19:51:30 updated: 2024/4/19 19:51:30 tags: Rabbit加密对称加密流密码密钥调度安全分析实际应用加密算法 第一章&#xff1a;引言 1. 加密算法的基本概念和应用 加密算法是一种通过对数据进行转换…

Llama3本地部署实现模型对话

1. 从github下载目录文件 https://github.com/meta-llama/llama3 使用git下载或者直接从github项目地址下载压缩包文件 git clone https://github.com/meta-llama/llama3.git2.申请模型下载链接 到Meta Llama website填写表格申请,国家貌似得填写外国,组织随便填写即可 3.…

Linux - sed (stream editor)

替换 my.yaml 的 ‘t’ 为 ‘AAA’ sed s/t/AAA/g my.yaml sed -n /^[as]/p my.yaml 这个命令的 -n 选项表示不自动打印每一行&#xff0c;/^[as]/p 是一个 sed 命令&#xff0c;/^[as]/ 是你想要匹配的正则表达式&#xff08;所有以 a | s 开头的行&#x…

【漏洞复现】锐捷 EG易网关 phpinfo.view.php 信息泄露漏洞

0x01 产品简介 锐捷EG易网关是一款综合网关产品&#xff0c;集成了先进的软硬件体系构架&#xff0c;并配备了DPI深入分析引擎、行为分析/管理引擎。这款产品能在保证网络出口高效转发的基础上&#xff0c;提供专业的流控功能、出色的URL过滤以及本地化的日志存储/审计服务。 …

蚂蚁云科技集团正式发布以正教育大模型,专注因材施教

4月12日,蚂蚁云科技集团成功举办“智以育人、慧正无界——以正教育大模型产品发布会”,该产品致力于智慧教育变革,让因材施教成为可能。 上海科学技术交流中心科技企业服务处处长陈霖博士、中国信通院华东分院院长廖运发、上海市科协常委马慧民博士等出席并致辞;南威软件集团执…

SQL注入简单总结

一、SQL注入是什么 SQL注入即&#xff1a;是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理员不知情的情况下实现非法操作&#xff0c;以此来实现欺骗数据库服…

武汉星起航:引领跨境电商新潮流,一站式孵化助力卖家轻松出海

武汉星起航电子商务有限公司&#xff0c;作为跨境电商领域的领军者&#xff0c;始终秉持“走出去”的战略理念&#xff0c;依托自营店铺的丰富经验和对跨境电商资源的深度整合&#xff0c;成功打造了一站式卖家孵化体系。这一体系集开店策划、运营教学、资源服务于一体&#xf…

Web安全知识

第二章 虚拟机运行架构&#xff1a; 1.寄居结构 2.原生架构 软件 注&#xff1a;Hyper-V是在Windows 2008操作系统上 附录 连接FTP服务器过程&#xff1a; 1.下载了软件&#xff1a; 2.连接到ftp://10.0.105.223/服务器&#xff08;访问老师课堂资源地址&#xff09; 关闭…

视频教程如何生成二维码?扫码看操作教程视频的制作技巧

产品使用教程的视频二维码如何制作呢&#xff1f;现在商家为了能够让用户可以快速的了解产品的使用说明或者安装教程&#xff0c;会选择将录制的相关视频生成二维码之后&#xff0c;打印到包装上或者通过客服人员发送给用户&#xff0c;用手机扫描对应二维码就可以获取教程&…

Spring Cloud OpenFeign底层实现原理

Spring Cloud OpenFeign底层实现原理 先说一下写这篇文章的一个原因&#xff0c;就是我被面试官吊打了&#xff0c;我只知道OpenFeign底层采用了RestTemplate进行调用&#xff0c;采用了动态代理&#xff0c;但是具体怎么实现的我就母鸡了。为了防止同样的地方摔倒&#xff0c…

【可靠数据传输的原理】

文章目录 可靠数据传输的原理可靠数据传输&#xff08;rdt&#xff09;的原理可靠数据传输&#xff1a;问题描述Rdt1.0&#xff1a; 在可靠信道上的可靠数据传输Rdt2.0&#xff1a;具有比特差错的信道rdt2.0&#xff1a;FSM描述rdt2.0&#xff1a;没有差错时的操作rdt2.0&#…

数图可视化品类空间管理系统入编《零售门店数字化赋能专项报告(2024年)》

数图可视化品类空间管理系统荣幸入编中国连锁经营协会发布的 《零售门店数字化赋能专项报告&#xff08;2024年&#xff09;》&#xff0c;报告以零售门店为切入点&#xff0c;通过引入“5P”的技术框架及梳理业内配套最佳实践方案&#xff0c;理出一套科学的、完整的零售门店数…

内存管理(C/C++)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

C语言转型之路:从C到C++的类与对象初探

欢迎来CILMY23的博客 本篇主题为 C语言转型之路&#xff1a;从C到C的类与对象初探 个人主页&#xff1a;CILMY23-CSDN博客 个人专栏系列&#xff1a; Python | C语言 | 数据结构与算法 | C 感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 写在前头…

蜂窝物联:蜂窝云平台全介绍

蜂窝云平台 PART 01 PC端展示平台 GIS地图 将地块嵌入到GIS地图展示&#xff0c;可以清晰展示各个地块所在地里位置&#xff0c;可以点击各个地块&#xff0c;在该界面可以清晰查看所选择地块的设备数据、监控画面、设备开关控制、基地介绍、基地图片等信息。 界面支持个化…