本文介绍了如何在JavaEE中执行响应后的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找到一种在响应后运行代码的方法,但未成功.

I tried, unsuccessfully, to find a way to run code after response.

在我的情况下,服务器向我发送数据以便让我完成工作,但是此操作可能会很长(例如,向5000个联系人发送SMS并检查谁收到了该消息).服务器期望HTTP 204 No Content立即响应,以确保已接收到数据.然后,我的web应用将执行操作并通过REST API发送状态.

In my case, a server sends me data in order to let me do my job but this action can be long (send SMS to 5000 contacts and check who received it, for example). The server expects HTTP 204 No Content response immediately to be sure that data has been received. Then my webapp will performs the action and send the status on a REST API.

我的问题是:如何发送响应然后执行代码?

My problem is: How to send the response and then execute code ?

现在我尝试:

  • doFilter
  • asyncContext
  • ExecutorService

在每种情况下,为了测试操作结束之前连接是否已关闭,我故意调用一个外部URL,该外部URL需要10秒钟的时间来回答.每次,我的服务器需要10秒钟来回答.

In each case, in order to test if the connection was closing before the end of my action, I call an external URL that takes 10s on purpose to answer. Each time, my server takes 10s to answer.

我的servlet一直挂着,等待代码结束.

My servlet is simply hanging on, waiting for the end of the code.

我无法使代码与Executors一起使用(这是新功能),但是即使在线程执行过程中遇到错误,我也想发送HTTP 204并另一方面处理错误.

I was unable to make the code works with Executors (new to this), but even if I got an error during the execution of the thread, I want to send HTTP 204 and handle error on another hand.

有一种简单的方法吗?

推荐答案

以下是我对这个问题的结论:

Here my conclusion on this question:

以下是发送响应后成功执行的示例代码:

Here a sample code of a successful execution done after response sent:

protected void doPost(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    final long startTime = System.currentTimeMillis(); //Start time to compare easily

    // MY ASYNC JOB
    Thread t1 = new Thread(new Runnable() {
        public void run()
        {
            try {
                Thread.sleep(10000);
                System.out.println("Long operation done.  /   " + (System.currentTimeMillis() - startTime));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }});
    t1.start();
    // END OF MY ASYNC

    // Servlet code here
    System.out.println("Will send the response.  /   " + (System.currentTimeMillis() - startTime));
    response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}

结果:我在17秒钟内在邮递员中收到了回复

Result: I received the response in 17ms in Postman

完成长时间的操作. /10011

Long operation done. / 10011

Servlet中的Spawn线程违反了Java EE规范,并且EJB无法在其中运行. 请参阅此处此处.以这种方式使用线程可能会导致线程饥饿.不允许在每台服务器上使用此命令(Tomcat不会阻止这种情况).

Spawn thread in a servlet is against Java EE spec and EJB doesn't work inside. See here or here. Use threads this way can lead to thread starvation. This is not allowed on every server (Tomcat doesn't prevent this).

可伸缩性是合同规定的,对我和读者来说,了解所有选择真的很有趣.而且我不知道我将在哪个服务器上托管我的Web应用程序!

Scalability is contractual and it is really interesting to know all options for me and readers. And I do not know on what server I will host my webapp !

ManagedExecutorService是Java EE 7的一部分.在我的情况下,该项目针对Java EE 6环境,因此我改用了ExecutorService.早些时候我遇到了一个问题:我无法在异步中访问请求的正文,并且发现:

ManagedExecutorService is part of Java EE 7. In my case, the project target a Java EE 6 environment so I used ExecutorService instead. Earlier I faced an issue: I can not access body of the request in my async, and I find this:

但是Servlet 3.1也是Java EE 7.因此,我的可运行构造函数要求将请求正文作为字符串.

But Servlet 3.1 is Java EE 7 too. So my runnable constructor ask for the request body as a String.

以下是ServletContextListener的示例代码:

Here a sample code for ServletContextListener:

public void contextInitialized(ServletContextEvent event) {
    //Executor
    executor = Executors.newCachedThreadPool();

    //Init Context
    app = event.getServletContext();
    app.setAttribute("executor", executor);
}

//Do not forget to implements contextDestroyed !
public void contextDestroyed(ServletContextEvent event) {
    try {
        executor.shutdown();
        while(!executor.awaitTermination(10, TimeUnit.SECONDS)){
            System.out.println("executor.awaitTermination");
        };
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

还有我的servlet:

And my servlet:

protected void doPost(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    final long startTime = System.currentTimeMillis(); //Start time to compare easily

    //Get my executor service and run a new async task
    ExecutorService serv = (ExecutorService) this.getServletContext().getAttribute("executor");
    serv.execute(new testAsync(startTime));

    // Servlet code here
    System.out.println("Will send the response.  /  " + (System.currentTimeMillis() - startTime));
    response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}


//My runnable
private class testAsync implements Runnable{ //Use Callable for Java 7+
    private long startTime;

    //Prior to Servlet 3.1, you have to give the request body instead of using asyncContext
    public testAsync(long pstart){
        this.startTime = pstart;
    }

    @Override
    public void run(){
        try {
            Thread.sleep(10000);
            System.out.println("Long operation done.  /   " + (System.currentTimeMillis() - this.startTime));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

该示例有效,并且似乎对我来说是最佳解决方案,因为我必须在异步任务中执行多线程处理.我将Tomcat用于开发,但是如果您使用其他工具,则必须使用ManagedExecutorService,因为它可能会阻止您在servlet中启动线程.

This example works and seems to be the best solution for me because I have to do multithreading in my async task. I use Tomcat for dev but if you use something else, you have to use ManagedExecutorService because it could prevents you to start thread in a servlet.

我也很惊讶,没有找到关于stackoverflow的简单快速示例.我能够编写代码,这要感谢这篇文章.

I am also very surprised to do not find a simple quick example on stackoverflow. I was able to code it thanks to this article.

我目前尚不了解JMS,将对其进行处理以查看它是否适合我的问题

I was not aware of JMS at this time and will work on it to see if it fit my problem

这篇关于如何在JavaEE中执行响应后的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 06:51