AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

需求背景

有一个接口实现合并文件,当文件过多时,预计要三分钟或者更长时间,这个时候前端调用的时候,由于后端长时间未返回结果,就会出现接口的超时的问题,于是就需要将任务异步执行,前端轮询查询任务的执行情况。考虑项目中接口代码已经完成,这个时候再修改比较麻烦,所以使用自定义注解,使用Spring AOP切点,异步执行任务,最后把任务结果缓存

流程图

image.png

代码实现

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public  @interface  RedisTaskStatus {
}

切点

@Aspect
@Component
public class RedisTaskStatusAspect {

    @Autowired
    private RedisUtil redisUtil;

    @Pointcut("@annotation(org.jeecg.common.aspect.annotation.RedisTaskStatus)")
    public void logPointCut() {

    }


    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point){
        String uuid = UUID.randomUUID().toString().replace("-", "");

        new Thread(() -> {
            Object result = null;
            try {
                result = point.proceed();
            } catch (Throwable throwable) {
                result = Result.error("执行任务异常"+throwable.getMessage());
            } finally {
		//结果缓存
                redisUtil.set(uuid, result, 600);
            }

        }, uuid).start();

        return Result.ok(uuid);
    }
}
  1. 这里我们返回了一个UUID给前端,前端定时轮询使用这个UUID调用查询结果的接口
  2. 将执行的结果存入到redis,这里由于前端会定时轮询接口,所以将结果存入缓存,前端调用的时候查询缓存,而不是查询数据库

方法调用

    @PostMapping(value = "/submit")
    @RedisTaskStatus
    public Result<?> submit(@RequestBody SubmitDataDTO submitDataDTO) {
        try {
            flowService.submit(submitDataDTO);
        } catch (Exception e) {
            return Result.error(e.getMessage());
        }
        return Result.ok();
    }

轮询接口

    @GetMapping(value = "/pollresult")
    public Result<?> pollResultRedisTaskStatus(@RequestParam(name="id") String id) {
        if(StringUtils.isEmpty(id)){
            Result.error("传入查询的值为空");
        }
        Result result= (Result) redisUtil.get(id);
        if(result!=null){
            log.info("轮询结果result:{}",result);
            return  result;
        }
	//自定义code 6056 标记任务未完成
        return Result.error(6056, "任务还没完成");
    }