V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MioZhang
V2EX  ›  Java

Springboot @AfterReturning 线程休眠的问题

  •  
  •   MioZhang · 2022-06-02 11:25:30 +08:00 · 1506 次点击
    这是一个创建于 936 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近刚接触 springboot 切面编程的相关内容,有个问题网上没太找到相关的解答,想问一下家人们~ 我现在定义了一个 @AfterReturning 的方法,在这个方法我执行了一个线程休眠 10 秒的操作。 但是我调用加入这个切点的方法时,为什么是需要调用 10 秒才能返回呀,这个 @AfterReturning 不是在方法执行完成返回结果之后执行的么? 相关代码如下:

        @Pointcut("@annotation(com.ice.hilf.contentmoderation.annotation.PicModeration)")
        public void picPointcut() {}
    
        @AfterReturning(pointcut = "picPointcut()", returning = "result")
        public void doAfterReturning(JoinPoint joinPoint, Object result) throws InterruptedException {
    
            System.out.println("Start aop");
            // 休眠,等待图片压缩完成
            Thread.sleep(10 * 1000);
            System.out.println("End sleep");
        }
    

    Controller 层方法上加上切面注解

        @PicModeration
        @PostMapping("/upload")
        @ResponseBody
        public ApiResponse<UniFileRtnVO> upload(
                @RequestParam("file")MultipartFile file,
                @RequestParam(value = "uploadType", required = false)Byte uploadType,
                @RequestParam("fileType") Byte fileType){
            ...
            return ApiResponse.success(rtnVO);
        }
    

    实际测试时结果就是每次调用这个接口要等 10s 才有返回值,是不是我对 @AfterReturning 的执行原理理解的有问题啊

    7 条回复    2022-06-02 14:13:53 +08:00
    BBCCBB
        1
    BBCCBB  
       2022-06-02 11:40:36 +08:00
    你 debug 一下, 在你的 afterReturing 里断点, 然后看一下线程执行堆栈.
    XhstormR02
        2
    XhstormR02  
       2022-06-02 11:41:11 +08:00 via Android
    不是多线程,如果你想让浏览器立即获取接口结果,你应该 hook tomcat 的方法
    iosyyy
        3
    iosyyy  
       2022-06-02 11:51:11 +08:00
    Thread.sleep(10 * 1000); 会挂起当前线程吧 所以不会返回 你新开一个线程用 future 来做异步返回的操作
    iosyyy
        4
    iosyyy  
       2022-06-02 11:52:14 +08:00
    而且你这操作应该用延时队列好一点吧
    LeegoYih
        5
    LeegoYih  
       2022-06-02 12:12:50 +08:00
    切面是通过动态代理实现的,可以简单的理解为把代码包了一层,大致执行流程如下:

    1. aop.before()
    2. res = controller.upload();
    3. aop.after()
    4. return res

    你在第 3 步睡了 10 秒,HTTP 接口也就会被 block 10 秒,因为他们用的是同一个线程执行的。
    OldCarMan
        6
    OldCarMan  
       2022-06-02 12:32:14 +08:00
    个人觉得,spring aop 是通过一个代理对象来完成切面编程的过程的,无论是这个过程的哪个步骤( Around...AfterThrowing )最终都是统一到这个代理对象中的方法一步步去完成这个过程的,这个过程是在同一个线程中完成的,你调用 Thread.sleep(10 * 1000),相当于在这个代理对象的方法中让当前线程休眠 10 秒钟,肯定是无法达到你“方法返回后休眠 10 秒钟”的需求的,简单的话建议使用异步队列的方式去完成你的需求。
    fanxasy
        7
    fanxasy  
       2022-06-02 14:13:53 +08:00
    你想要的是 @After ,不是 @AfterReturning
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1900 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:15 · PVG 00:15 · LAX 08:15 · JFK 11:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.