Spring @Async 的使用与实现的示例代码
发布时间 - 2026-01-11 02:57:03 点击率:次首先Spring AOP有两个重要的基础接口,Advisor和PointcutAdvisor,接口声明如下:

Advisor接口声明:
public interface Advisor {
Advice getAdvice();
boolean isPerInstance();
}
PointcutAdvisor的接口声明:
public interface PointcutAdvisor extends Advisor {
/**
* Get the Pointcut that drives this advisor.
*/
Pointcut getPointcut();
}
PointcutAdvisor用来获取一个切点以及这个切点的处理器(Advise)。
@Async注解使用后置处理器BeanPostProcessor的子类AsyncAnnotationBeanPostProcessor来实现bean处理 :
AsyncAnnotationAdvisor继承了PointcutAdvisor接口。并且在AsyncAnnotationBeanPostProcessor实现了其父类接口的BeanFactoryAware中的setBeanFactory初始化。Spring一旦创建beanFactory回调成功,就会回调这个方法。保证Advisor对象最先被初始化。
@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;
}
}
具体的后置处理是通过AsyncAnnotationBeanPostProcessor的后置bean处理是通过其父类AbstractAdvisingBeanPostProcessor来实现的。AbstractAdvisingBeanPostProcessor提供的后置bean处理方法对所有的自定义注解的bean处理方法时通用的。其具体的代码如下:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
/*
* bean对象如果是一个ProxyFactory对象。ProxyFactory继承了AdvisedSupport,而 AdvisedSupport又继承了Advised接口。这个时候就把不同的Advisor添加起来。
*
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());
}
可以看得出来,isEligible用于判断这个类或者这个类中的某个方法是否含有注解。这个方法最终进入到AopUtils的canApply方法中间:
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;
}
}
这里的advisor就是AsyncAnnotationAdvisor对象。然后调用AsyncAnnotationAdvisor对象的getPointcut()方法,得到了Pointcut对象。在AOP规范中间,表示一个具体的切点。那么在方法上注释@Async注解,就意味着声明了一个切点。
然后再根据Pointcut判断是否含有指定的注解。
切点的执行
由于生成了JDK动态代理对象,那么每一个方法的执行必然进入到JdkDynamicAopProxy中的invoke方法中间去执行:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
重点的执行语句:
// 获取拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 根据拦截器来执行
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
@Async注解的拦截器是AsyncExecutionInterceptor,它继承了MethodInterceptor接口。而MethodInterceptor就是AOP规范中的Advice(切点的处理器)。
自定义注解
由于其bean处理器是通用的,所以只要实现PointcutAdvisor和具体的处理器就好了。首先自定义一个注解,只要方法加入了这个注解,就可以输出这个方法的开始时间和截止时间,注解的名字叫做@Log:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
}
定义一个简单的方法用于测试:
public interface IDemoService {
void add(int a, int b);
String getName();
}
@Service
public class DemoServiceImpl implements IDemoService {
@Log
public void add(int a, int b) {
System.out.println(Thread.currentThread().getName());
System.out.println(a + b);
}
@Override
public String getName() {
System.out.println("DemoServiceImpl.getName");
return "DemoServiceImpl";
}
}
定义Advisor:
public class LogAnnotationAdvisor extends AbstractPointcutAdvisor {
private Advice advice;
private Pointcut pointcut;
public LogAnnotationAdvisor() {
this.advice = new LogAnnotationInterceptor();
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public boolean isPerInstance() {
return false;
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) {
Assert.notNull(asyncAnnotationType, "'asyncAnnotationType' must not be null");
Set<Class<? extends Annotation>> asyncAnnotationTypes = new HashSet<Class<? extends Annotation>>();
asyncAnnotationTypes.add(asyncAnnotationType);
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
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 = AnnotationMatchingPointcut.forMethodAnnotation(asyncAnnotationType);
if (result == null) {
result = new ComposablePointcut(cpc).union(mpc);
} else {
result.union(cpc).union(mpc);
}
}
return result;
}
}
定义具体的处理器:
public class LogAnnotationInterceptor implements MethodInterceptor, Ordered {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("开始执行");
Object result = invocation.proceed();
System.out.println("结束执行");
return result;
}
}
定义@Log专属的BeanPostProcesser对象:
@SuppressWarnings("serial")
@Service
public class LogAnnotationBeanPostProcesser extends AbstractBeanFactoryAwareAdvisingPostProcessor {
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
LogAnnotationAdvisor advisor = new LogAnnotationAdvisor();
advisor.setAsyncAnnotationType(Log.class);
this.advisor = advisor;
}
}
对bean的后置处理方法直接沿用其父类的方法。当然也可以自定义其后置处理方法,那么就需要自己判断这个对象的方法是否含有注解,并且生成代理对象:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
for (Method method : methods) {
if (method.isAnnotationPresent(Log.class)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
System.out.println(proxyFactory);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
}
return bean;
}
测试注解是否是正常运行的:
public class Main {
public static void main(String[] args) {
@SuppressWarnings("resource")
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
IDemoService demoService = context.getBean(IDemoService.class);
demoService.add(1, 2);
demoService.getName();
//// AsyncAnnotationAdvisor
// AsyncAnnotationBeanPostProcessor
}
}
输出:
开始执行 main 3 结束执行 DemoServiceImpl.getName
功能一切正常。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Spring
# @Async
# 使用
# Spring中@Async用法详解及简单实例
# 浅谈Spring @Async异步线程池用法总结
# 关于Spring注解@Async引发其他注解失效的解决
# JAVA 中Spring的@Async用法总结
# Spring中@Async注解执行异步任务的方法
# Spring处理@Async导致的循环依赖失败问题的方案详解
# Java Spring的@Async的使用及注意事项示例总结
# 自定义
# 其父
# 继承了
# 来实现
# 拦截器
# 回调
# 是一个
# 就会
# 子类
# 就把
# 看得
# 然后再
# 这个时候
# 于其
# 正常运行
# 大家多多
# 就可以
# 截止时间
# 类中
# 判断是否
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
如何在阿里云域名上完成建站全流程?
浅析上传头像示例及其注意事项
高防服务器租用首荐平台,企业级优惠套餐快速部署
iOS验证手机号的正则表达式
Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道
如何在万网开始建站?分步指南解析
Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
如何在IIS7上新建站点并设置安全权限?
Laravel如何配置Horizon来管理队列?(安装和使用)
如何生成腾讯云建站专用兑换码?
如何解决hover在ie6中的兼容性问题
html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】
,交易猫的商品怎么发布到网站上去?
Laravel的.env文件有什么用_Laravel环境变量配置与管理详解
Laravel怎么为数据库表字段添加索引以优化查询
网站制作价目表怎么做,珍爱网婚介费用多少?
Google浏览器为什么这么卡 Google浏览器提速优化设置步骤【方法】
如何快速搭建安全的FTP站点?
laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法
如何做网站制作流程,*游戏网站怎么搭建?
移动端脚本框架Hammer.js
微信小程序 scroll-view组件实现列表页实例代码
javascript日期怎么处理_如何格式化输出
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
历史网站制作软件,华为如何找回被删除的网站?
零基础网站服务器架设实战:轻量应用与域名解析配置指南
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
瓜子二手车官方网站在线入口 瓜子二手车网页版官网通道入口
Win11搜索不到蓝牙耳机怎么办 Win11蓝牙驱动更新修复【详解】
如何注册花生壳免费域名并搭建个人网站?
在线制作视频的网站有哪些,电脑如何制作视频短片?
Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践
Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程
百度浏览器如何管理插件 百度浏览器插件管理方法
Laravel如何自定义错误页面(404, 500)?(代码示例)
手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?
Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
googleplay官方入口在哪里_Google Play官方商店快速入口指南
使用C语言编写圣诞表白程序
html5如何实现懒加载图片_ intersectionobserver api用法【教程】
在centOS 7安装mysql 5.7的详细教程
Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
微信小程序 配置文件详细介绍
如何快速搭建高效WAP手机网站?
如何在 React 中条件性地遍历数组并渲染元素
品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?

