Spring 注解:@Async

Spring 异步@Async注解用法 Spring @Async注解用法总结 Spring @Async基本用法示例 一、概述在日常开发的工作中,经常会使用异步进行开发。Spring 提供一个简单的注解 @Async ,即可实现异步的开发,无需创建线程池,简单明了。本文将整理@Async的常见用法,包括:基础入门,获取返回值,配置线程池,异常处理等。@Async 注解实现原理,请自行查看源码,从:org.springframework.aop.interceptor.开始...1、本文相对详细的记录@Async 注解的常见用法,可以满足日常大部分的开发需求。2、注意一点: 在同一个类中,是可以存在异步方法。 阅读详情

作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)

一、概述

1、Java执行顺序默认是同步的,代码是逐条执行,当需要调用三方的接口或者耗时的方法时可能会造成接口的响应时间变长。有些时候我们不关心三方接口的返回结果,那么以前的话是使用多线程来解决这个问题,将耗时的方法或者请求三方的方法单开线程来处理。

2、使用@Async注解的方法可以使方法被异步调用,底层其实也是使用的线程池来实现的。

二、源码分析

1、@Async
在需要异步执行的方法上添加该注解。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {

	/**
	 * A qualifier value for the specified asynchronous operation(s).
	 * <p>May be used to determine the target executor to be used when executing
	 * the asynchronous operation(s), matching the qualifier value (or the bean
	 * name) of a specific {@link java.util.concurrent.Executor Executor} or
	 * {@link org.springframework.core.task.TaskExecutor TaskExecutor}
	 * bean definition.
	 * <p>When specified on a class-level {@code @Async} annotation, indicates that the
	 * given executor should be used for all methods within the class. Method-level use
	 * of {@code Async#value} always overrides any value set at the class level.
	 * @since 3.1.2
	 */
	String value() default "";
}

(1)、可在类或方法上使用,在类上使用表明该类的所有方法都是异步执行,一般是用在方法上。
(2)、默认使用的线程池是SimpleAsyncTaskExecutor,可以指定已有的或者自定义的执行器,@Async(“执行器名”)
(3)、方法的调用应该是类之间的,如果是同一个类中的相互调用,比如一个没有@Async注解的方法A调用有@Async注解的方法B,方法B是不会异步执行的,原理跟@Transactional注解一样,同一个类的方法调用不会走代理。

2、@EnableAsync

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

	//该属性用来支持用户自定义异步注解,默认扫描spring的@Async和EJB3.1的@code @javax.ejb.Asynchronous
	Class<? extends Annotation> annotation() default Annotation.class;

	//默认使用jdk代理,true是CGLIB代理,两者的区别就是接口有实现时Spring会选择使用jdk反射代理,没有实现会使用cglib
	boolean proxyTargetClass() default false;

	//标明异步通知将会如何实现,默认PROXY,如需支持同一个类中非异步方法调用另一个异步方法,需要设置为ASPECTJ
	AdviceMode mode() default AdviceMode.PROXY;

	//标明异步注解bean处理器应该遵循的执行顺序,默认最低的优先级(Integer.MAX_VALUE,值越小优先级越高)
	int order() default Ordered.LOWEST_PRECEDENCE;

}

在启动类上需要添加@EnableAsync注解,加上该注解才能生成Async的代理。

3、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() {
		//这里会判断是否有使用@EnableAsync
		Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
		//重点,这个类会生成Async的代理
		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);
		}
		//读取@EnableAsync的属性,初始化
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}
}

4、AsyncAnnotationBeanPostProcessor

public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
	...
	//省略了该类的其他属性和方法
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		//这里是重点,生成了Async的Advisor
		AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
		if (this.asyncAnnotationType != null) {
			advisor.setAsyncAnnotationType(this.asyncAnnotationType);
		}
		advisor.setBeanFactory(beanFactory);
		this.advisor = advisor;
	}

}

AsyncAnnotationBeanPostProcessor类创建了Async的Advisor,然后AsyncAnnotationAdvisor类初始化了通知和切点

5、AsyncAnnotationAdvisor

public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

	private Advice advice;

	private Pointcut pointcut;

	/**
	 * 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
	 * @since 5.1
	 * @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
	 */
	@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);
		//切点就是使用了@Async注解的方法
		this.pointcut = buildPointcut(asyncAnnotationTypes);
	}


	
	
	protected Advice buildAdvice(
			@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
		//使用拦截器做通知
		AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
		interceptor.configure(executor, exceptionHandler);
		return interceptor;
	}

	/**
	 * 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);
	}

}

可以看到,通知是AsyncExecutionInterceptor,该类实现了MethodInterceptor,这是cglib代理的核心接口;切点就是使用了@Async注解的方法。

6、AsyncExecutionInterceptor

public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {
	...
	
	@Override
	@Nullable
	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");
		}
		//将被代理对象的方法转为task
		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());
	}

...
}

7、AbstractBeanFactoryAwareAdvisingPostProcessor继承了BeanPostProcessor,重写了postProcessAfterInitialization方法,在Spring初始化容器创建bean后会调用这个方法,这个方法就会判断类是否有代理,有则生成代理类。

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

总结:
1、@EnableAsync注解生成AsyncAnnotationBeanPostProcessor类。
2、AsyncAnnotationBeanPostProcessor创建了AsyncAnnotationAdvisor类,这个类封装了通知(拦截器)和切点(使用了@Async 的方法)。
3、AsyncAnnotationBeanPostProcessor实现了BeanPostProcessor接口,最终会执行postProcessAfterInitialization方法,生成代理类。

Spring 框架——@Async 注解 同步调用特点:调用方在发起方法调用后,必须等待被调用的方法完成并返回结果之后,才能继续执行后续的操作(即会阻塞)。在同步调用中,调用方和被调用方的执行顺序是严格按照调用顺序进行的。适用场景:依赖顺序:当某个操作必须在另一个操作完成后才能进行时。简单任务:当任务执行时间短且没有并发问题时。确保执行顺序:需要确保多个步骤按顺序完成,比如数据库事务处理。异步调用特点:调用方发起方法调用后,不必等待被调用的方法完成,而是可以继续执行后续的操作。 阅读详情

相关推荐

5分钟搞懂语义通信:如何用深度学习让AI理解你的真实意图?

本文深入解析了语义通信如何利用深度学习技术,实现从传统‘比特保真’到‘语义保真’的范式转移。通过介绍基于神经网络的端到端系统架构、编解码技术及实战案例,阐明AI如何理解并高效传递信息核心意图,为6G时代的人机交互奠定基础。

weixin_29191669的博客 262

Spring之@Async注解(异步调用)

本文讲述@Async注解,在Spring体系中的应用。本文仅说明@Async注解的应用规则,对于原理,调用逻辑,源码分析,暂不介绍。对于异步方法调用,从Spring3开始提供了@Async注解,该注解可以被标注在方法上,以便异步地调用该方法。调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行。 在项目应用中,@Async调用线程池,推荐使用自定义线程池的模式。自定义线程池常用方案:重新实现接口AsyncConfigurer。 ..

宇智波小强的博客 1639

手把手教你复现KDD 2024时空预测顶会论文:以UniST和ImputeFormer为例的代码实战与避坑指南

本文详细指导如何复现KDD 2024顶会论文中的UniST和ImputeFormer模型,涵盖环境配置、数据处理、模型训练及评估等关键步骤。通过实战案例和避坑指南,帮助研究者掌握时空预测与插补技术,提升在智慧城市、交通管理等领域的应用能力。

weixin_29204205的博客 279

Spring之@Async异步注解

1.注解介绍 @Async注解,该注解可以被标注在方法上,以便异步地调用该方法。调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行。在项目应用中,@Async调用线程池,推荐使用自定义线程池的模式。自定义线程池常用方案:重新实现接口AsyncConfigurer。 2.Spring的线程池 1. SimpleAsyncTaskExecutor:,这个类不重用线程,默认每次调用都会创建一个新的线程。 2. SyncTaskExecu

sun134911的博客 1万+

(NOI)打表骗分过样例,暴力枚举出奇迹1.8.22题解

                                                                                                                                                           48818 B题解 #include &lt;iostream&gt; u...

Owen20071026的博客 3127

NRF24L01学习操作教程(二)——NRF实现一对一,一对多通讯

以上内容详细介绍了,使用NRF24L01实现1对1单向通讯、1对1双向通讯、1对多双向通讯。

Joseph Wen的博客 7388

Spring中@Async注解的使用

通常,在Java中的方法调用都是同步调用,比如在A方法中调用了B方法,则在A调用B方法之后,必须等待B方法执行并返回后,A方法才可以继续往下执行。 这样容易出现的一个问题就是如果B方法执行时间较长,则可能会导致调用A的请求响应迟缓 或者超时,验证影响用户体验。 为了解决这种问题,可以使用Spirng的注解@Async来用异步调用的方式处理。

Java修炼记 4408

【深度学习-番外1】Win10系统搭建VSCode+Anaconda+Pytorch+CUDA深度学习环境和框架全过程

本文将介绍在Windows 10系统下搭建深度学习环境的完整过程,包括安装Anaconda、CUDA、NVIDIA显卡驱动以及Pytorch框架。后续本专栏的Python语言下的深度学习环境都以本篇搭建的为准。

fengzhuqiaoqiu的博客 3996

Spring注解之@Async

在Spring框架中,@Async注解依赖于Spring的AOP机制,而AOP是通过动态代理来实现的。当你手动使用new来实例化类时,Spring并不能管理这个实例,因此Spring的AOP机制也无法为其创建代理对象,导致像@Async这样的注解失效。

qq_48990935的博客 1435

PCB设计AD规则设置(按照嘉立创设置)

按照嘉立创的相关加工能力进行设置: 1.Hole Size(钻孔孔径) 嘉立创要求钻孔孔径在0.2-6.3mm,并给了公差(如下图给出了钻孔孔径和公差) 规则设置位置:Manufacturing->Hole Size,这里就改一下数值,最小设置为0.2mm,最大设置为6.3mm 2.Width(线宽) 嘉立创要求线宽多层板双层板最小为3.5mil,单双层板最小为5mil(如下图给出了线宽) 规则设置位置:Routing->Width,我目前只画过双层板,按我的设置如下,最小的线宽设置为10

subtitle_的博客 4万+

RK3568平台开发系列讲解(项目篇)手写数字识别

📢 本篇章带大家基于飞桨(PaddlePaddle),完成一个简单的手写数字识别任务。

内核笔记 1182

【@Async】一文带你深入学习Spring注解之@Async使用

Spring Boot的@Async注解提供了简单且强大的方式来实现异步处理。通过启用异步支持、定义异步方法并自定义TaskExecutor,可以高效地处理各种异步任务。掌握@Async注解的使用和原理,有助于提升应用程序的性能和响应速度。但是其局限性也是非常明显的,因此,要想用好该@Async注解,还是需要在此基础上加以扩展。我是Wasteland,下期文章再见!

weixin_51360020的博客 6916

Open-Sora代码详细解读(1):解读DiT结构

目前开源的DiT视频生成模型不是很多,Open-Sora是开发者生态最好的一个,涵盖了DiT、时空DiT、3D VAE、Rectified Flow、因果卷积等Diffusion视频生成的经典知识点。本篇博客从Open-Sora的代码出发,深入解读背后的原理。

沉迷单车的追风少年 2263

Spring @Async 注解的使用以及原理(一)

Spring中用@Async注解标记的方法,称为异步方法,它会在调用方的当前线程之外的独立的线程中执行,其实就相当于我们自己new Thread(()-&gt; System.out.println("hello world !"))这样在另一个线程中去执行相应的业务逻辑。本篇先只讲@Async的使用,后面会分析它实现原理。 @Async注解使用条件: @Async注解一般用...

灵颖桥人的博客 7万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Spring之@Async注解

EnableAsync 注解需要和 @Async 注解搭配使用,这篇博文我们就分析这两个注解是如何搭配使用的如果 bean 已经是一个代理对象则给 Advised 对象(代理对象)添加一个Advisor,否则进行动态代理。

好记性不如烂笔头 737

Spring @Async注解

1.@Async @Async源码@Async的value属性可以指定执行线程池,当其被标注在类或者方法上,用于实现方法的异步执行,当被标注在类上,表明类中的所有方法都被指定的异步执行器执行。 2.实现原理 为了更基础的分析异步调用背后的实现原理,这里选择使用xml配置文件的方式。使用xml配置文件方式时,一般会配置如下元素: <task:annotation-driven executor="myExecutor" exception-handler="exceptionHandler"/

勇往直前的专栏 1296

Spring异步注解@Async

通过AsyncExecutionAspectSupport源码,我们可以知道线程池会首先通过用户自己配置的为准,找不到就使用默认的线程池,Spring会优先搜索TaskExecutor类型的bean或者名为taskExecutor的Executor类型的bean,如果都不存在的话,会使用SimpleAsyncTaskExecutor(不推荐使用)执行器。所以,我们可以自定义线程池,然后注入spring中,将bean的名字放到@Async注解的value值即可。

Ascend1977的博客 1061
上一篇: Java接口有多个实现类,按照排序调用每个实现类重写的方法
下一篇: Spring:ApplicationEventPublisher事件发布与监听
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值