springboot怎么利用aop实现接口异步
springboot怎么利用aop实现接口异步
小编给大家分享一下springboot怎么利用aop实现接口异步,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
一、前言
在项目中发现有接口(excel导入数据)处理数据需要耗时比较长的时间,是因为数据量比较大,同时数据的校验需要耗费一定时间,决定使用一种通用的方法解决这个问题。
解决方案:通过aop使接口异步处理,前端轮询另外一个接口查询进度。
目标:
1接口上一个注解即可实现接口异步(优化:可以通过header参数动态控制是否异步)
2一个方法实现进度条的更新
二、时序图
三、功能演示
四、关键代码
Controller
@EnableAsync是自已定义注解更新缓存进度asyncService.updatePercent(per);
@EnableAsync@RequestMapping(value="test",method=RequestMethod.POST)@ApiOperation(value="接口测试")@ApiImplicitParams({@ApiImplicitParam(name="num",value="数字",required=true,dataType="int",paramType="query",defaultValue="1")})publicObjectdemo(Integernum)throwsInterruptedException{for(inti=0;i<15;i++){Thread.sleep(1000);//计算百分比Stringper=BigDecimal.valueOf(i).divide(BigDecimal.valueOf(15),2,RoundingMode.HALF_DOWN).toString();//更新redis缓存进度asyncService.updatePercent(per);}Integerb=100;returnResult.success(String.format("线程变量值:%s,100除以%s的结果是%s",RequestHolder.get(),num,b/num));}
AsyncAop
importcn.hutool.core.util.IdUtil;importcom.asyf.demo.common.Result;importcom.asyf.demo.common.pojo.RequestHolder;importcom.asyf.demo.service.AsyncService;importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Pointcut;importorg.aspectj.lang.reflect.MethodSignature;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;importjavax.servlet.http.HttpServletRequest;@Aspect@Component@Slf4jpublicclassAsyncAop{@AutowiredprivateAsyncServiceasyncService;@Pointcut("@annotation(com.asyf.demo.common.aop.EnableAsync)")publicvoidcostTimePointCut(){}@Around("costTimePointCut()")publicObjectaround(ProceedingJoinPointpoint)throwsThrowable{longbeginTime=System.currentTimeMillis();//请求headerServletRequestAttributesservletRequestAttributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequestrequest=servletRequestAttributes.getRequest();RequestHolder.set(request.getHeader("dateFormat"));//异步消息Stringid=IdUtil.simpleUUID();AsyncMsgasyncMsg=newAsyncMsg();asyncMsg.setId(id);//异步返回值Objectresult=Result.success(asyncMsg);StringrequestHolder=RequestHolder.get();//异步执行asyncService.async(requestHolder,asyncMsg,point);//执行时长(毫秒)longtime=System.currentTimeMillis()-beginTime;logCostTime(point,time);returnresult;}privatevoidlogCostTime(ProceedingJoinPointpoint,longtime){MethodSignaturesignature=(MethodSignature)point.getSignature();StringclassName=point.getTarget().getClass().getName();StringmethodName=signature.getName();log.info("class:{}method:{}耗时:{}ms",className,methodName,time);}}
AsyncService
实现异步消息的更新
异步消息的进度信息传递通过本地线程与redis实现
importcn.hutool.core.exceptions.ExceptionUtil;importcom.asyf.demo.common.aop.AsyncMsg;importcom.asyf.demo.common.pojo.AsyncHolder;importcom.asyf.demo.common.pojo.RequestHolder;importcom.asyf.demo.service.AsyncService;importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.stereotype.Service;importjava.util.concurrent.TimeUnit;@Service@Slf4jpublicclassAsyncServiceImplimplementsAsyncService{@AutowiredprivateRedisTemplateredisTemplate;@Overridepublicvoidasync(StringrequestHolder,AsyncMsgasyncMsg,ProceedingJoinPointpoint){newThread(newRunnable(){@Overridepublicvoidrun(){Stringid=asyncMsg.getId();//请求线程变量-传递请求线程参数RequestHolder.set(requestHolder);//异步消息线程变量-传送id到实际方法以便方法更新进度AsyncHolder.set(asyncMsg);//执行方法try{redisTemplate.opsForValue().set(id,asyncMsg,60,TimeUnit.MINUTES);Objectresult=point.proceed();asyncMsg.setResult(result);asyncMsg.setStatus("0");redisTemplate.opsForValue().set(id,asyncMsg,60,TimeUnit.MINUTES);}catch(Throwablethrowable){log.error(ExceptionUtil.stacktraceToString(throwable));asyncMsg.setStatus("-1");asyncMsg.setResult(throwable.getLocalizedMessage());redisTemplate.opsForValue().set(id,asyncMsg,60,TimeUnit.MINUTES);}}}).start();}@OverridepublicvoidupdatePercent(Stringper){AsyncMsgasyncMsg=AsyncHolder.get();asyncMsg.setPercent(per);redisTemplate.opsForValue().set(asyncMsg.getId(),asyncMsg,60,TimeUnit.MINUTES);}}
看完了这篇文章,相信你对“springboot怎么利用aop实现接口异步”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
推荐阅读
-
springboot实现基于aop的切面日志
本文实例为大家分享了springboot实现基于aop的切面日志的具体代码,供大家参考,具体内容如下通过aop的切面方式实现日志...
-
SpringBoot定时任务功能怎么实现
-
SpringBoot中的@Import注解怎么使用
-
SpringBoot整合Lombok及常见问题怎么解决
-
springboot图片验证码功能模块怎么实现
-
Springboot+SpringSecurity怎么实现图片验证码登录
-
SpringBoot注解的知识点有哪些
SpringBoot注解的知识点有哪些这篇“SpringBoot注...
-
SpringBoot2.x中management.security.enabled=false无效怎么解决
-
springboot怎么禁用某项健康检查
springboot怎么禁用某项健康检查今天小编给大家分享一下sp...
-
SpringBoot2怎么自定义端点