【问题标题】:Call another method after Spring MVC handler returns在 Spring MVC 处理程序返回后调用另一个方法
【发布时间】:2015-10-17 07:29:56
【问题描述】:

我有一个要求,我需要从休息控制器返回一些状态/长值,然后执行代码以发送推送通知。

@RequestMapping(value="/create")
public String createTicket() throws InterruptedException {
    // code to create ticket
    return "ticket created";
    // need to call sendPushNotifiction() after I return status
}

    public void sendPushNotifiction() throws InterruptedException {
    // code to send push notification
    System.out.println("Sent push notification successfully!!");    
}

有人可以告诉我如何实现这一目标吗?是否可以为此使用 Spring AOP?我不认为线程只会在返回后保证 sendPushNotifiction 方法的执行。那么有什么方法可以有效地实现这一目标呢? 提前致谢

【问题讨论】:

    标签: spring spring-mvc spring-aop


    【解决方案1】:

    我认为这可能是异步处理的一个很好的用例。春天有good support。准确地说,你需要

    1. @Async注释sendPushNotifiction
    2. @EnableAsync注解一些配置类。
    3. 在返回语句之前调用sendPushNotifiction()。执行流程不会等待sendPushNotifiction 完成。

    如果不起作用,请尝试在单独的服务中编码sendPushNotifiction

    【讨论】:

    • 谢谢桑杰,让我试试这个。
    • 如果从控制器返回后需要启动异步函数怎么办?比如说,异步函数只是增加一个数字并将结果发布到您从控制器返回的通量流,它甚至在您返回之前就完成了?
    【解决方案2】:

    创建另一个方法,它首先调用createTicket() 方法,然后调用sendPushNotifiction()。这将完成这项工作。在我看来,这是最简单的方法。

    【讨论】:

    • 感谢 YoungHobbit,但在我的场景中,我想先从方法返回作为确认,然后执行一些代码来处理某些内容。你能告诉我实现这一目标的最佳方法吗?
    • @PratapA.K 可以存储ACK消息并在完成sendPushNotifiction()方法后返回。这对你来说不可能吗?
    • 这是可能的,但要求是,我需要向不同的应用程序发送 ACK 并将通知推送到不同的应用程序。所以在发送推送通知之前,我会做很多复杂的数学运算,这会消耗大量时间。所以我不希望另一个应用程序为了 ACK 继续等待这么久。希望你得到我。
    • @PratapA.K 然后你可以启动一个只发送通知并退出的线程。您可以立即发送 ACL。我知道启动一个线程也需要一些时间。我们能做些什么?
    • 感谢 YoungHobbit。是的@Sainik Ku​​mar Singhal:答案对我有用。我已经有一个用于 /create 请求的拦截器,我可以利用它。再次感谢!!
    【解决方案3】:

    createTicket()是spring调用的。不能直接调用。可以使用org.springframework.web.servlet.HandlerInterceptor。只需从postHandle()afterCompletion()方法调用你的sendPushNotifiction()方法 你的 HandlerInterceptor

        package com.sample.interceptor;
    
       import javax.servlet.http.HttpServletRequest;
       import javax.servlet.http.HttpServletResponse;
    
       import org.springframework.web.servlet.HandlerInterceptor;
       import org.springframework.web.servlet.ModelAndView;
    
       public class NotifictionHandlerInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        //do nothing
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    
        //call your method here
        //call sendPushNotifiction()
    
    }
    

    }

    并在 spring-mvc 上下文中注册你的处理程序

        <mvc:interceptors>
    <bean class="com.sample.NotifictionHandlerInterceptor" />
       </mvc:interceptors>
    

    【讨论】:

    • Kumar:你能提供一段代码吗?是的,在完成 Rest 请求后,我需要执行另一段代码。
    • 你能用示例代码更新你的答案吗?
    • 感谢 Sainik:我认为这符合我的要求。让我在星期一之前尝试一次你的答案,然后再接受
    • 嗨@ Sainik :如果我的 sendPushNotification() 方法需要参数怎么办?如何从 createTicket 传递参数 --> sendPushNotification?
    • 您可以将这些放入请求中的 createTicket 方法中并在 HandlerInterceptor 中检索
    【解决方案4】:

    你可以这样调用:

    @RequestMapping(value="/create")
    public void create(){
    createTicket();
    sendPushNotifiction();
    }
    
    public String createTicket() throws InterruptedException {
        // code to create ticket
        return "ticket created";
        // need to call sendPushNotifiction() after I return status
    }
    
        public void sendPushNotifiction() throws InterruptedException {
        // code to send push notification
        System.out.println("Sent push notification successfully!!");    
    }
    

    【讨论】:

    • 控制器在这个例子中没有返回任何东西。 “创建的票”在深渊中消失了。
    【解决方案5】:

    我同意 youngHobbit 的解决方案,你可以像下面那样做

    @RequestMapping(value="/create")
    public String entryMethod() throws InterruptedException {
       String response = createTicket();
       sendPushNotifiction();
       return response ;
    }
    
    public String createTicket() throws InterruptedException {
        // code to create ticket
        return "ticket created";
        // need to call sendPushNotifiction() after I return status
    }
    
        public void sendPushNotifiction() throws InterruptedException {
        // code to send push notification
        System.out.println("Sent push notification successfully!!");    
    }
    

    虽然另一种解决方案可以在您完成第一个方法后将请求转发/重定向到另一种方法。但是,如果它以简单、清晰和易读的方式解决您的目的,请采用第一种方法

    AOP 基本上是用于处理您想要跨应用程序处理的横切关注点,不应该用于像这样的非常特定的目的。为什么要引入额外的复杂性

    【讨论】:

    • 感谢 M Sach 的快速回复。但是使用这种方法,我无法将状态从 createTicket 发送回调用者。我的 createTicket 是一个 rest 方法,所以当用户调用这个方法时,我需要先发送 Http 状态,然后再向其他用户推送通知
    • 现在,在 entryMethod() 中,我们首先调用 sendPushNotifiction() 然后返回响应。但是我想知道是否可以先返回然后调用sendPushNotifiction方法。
    • 然后进行重定向请求
    【解决方案6】:

    另一种方法是将 sendPushNotification() 的执行推迟到某个线程/线程池。在返回之前,使用队列将处理入队,然后在你的线程中出列并处理。

    但是,您应该注意将您的请求链接到真正的调用者并处理失败等问题。

    网络上到处都是例子。查找 java.util.concurrent 示例、执行器、...

    【讨论】:

      【解决方案7】:

      HandlerInterceptor 是解决方案,但代码比预期的要复杂一些。这是一个代码建议,通过将整个解决方案放在一个类中来使其更简单:

      @RequestMapping(value = "/create")
      public String createTicket() throws InterruptedException {
          String ticket = "ticket created";
          result.set(ticket); // Save the ticket to be used after response
          return ticket;
      }
      
      public void sendPushNotifiction(String ticket) throws InterruptedException {
          System.out.println("Sent push notification successfully!!");
      }
      
      private static final ThreadLocal<String> result = new ThreadLocal<String>();
      
      @Bean
      public MappedInterceptor interceptor() {
          return new MappedInterceptor(Arrays.array("/create"), new HandlerInterceptor() {
              @Override
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                  // Get the saved object and clean for the next request
                  String ticket = result.get();
                  result.set(null);
      
                  // Execute after response
                  sendPushNotifiction(ticket);
              }
          });
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-03
        • 1970-01-01
        • 2013-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-19
        相关资源
        最近更新 更多