关闭Grizzley服务器时,未调用Jersey资源@PreDestroy

时间:2018-10-30 14:57:43

标签: jersey-2.0 server-sent-events grizzly

我正在运行一个简单的Jersey / Grizzly HTTP服务器,该服务器具有处理服务器发送的事件的资源。

该资源需要手动处理一个Timer实例,才能向所有连接的SSE客户端发送一些保持活动状态的数据,因此我使用@PostConstruct@PreDestroy注释来构造和取消该计时器(及其后台线程)。

该应用程序是一个简单的控制台应用程序,没有嵌入到任何容器环境(例如Tomcat)中。启动Web服务器后,它将等待简单的System.in.read()并通过在Grizzly HTTP服务器实例上调用shutdownNow()再次关闭服务器。

连接到SSE资源时,将实例化资源类并启动计时器。与服务器断开连接后,经过短暂的延迟,资源再次被销毁,一切都很好。

但是,由于SSE资源的性质,客户端可能会无休止地连接,因此也可以在内部保留资源实例。

如果我现在尝试在连接客户端的情况下通过调用shutdownNow()来关闭服务器,则服务器实例将正常关闭,但不会调用任何@PreDestroy的活动资源方法。这会导致我的Timer实例资源仍然存在,并且由于计时器仍然处于活动状态,因此即使HTTP服务器已经关闭,这也将使Java进程继续运行。

是否可以检索所有当前活动的资源实例,因此我可以在关闭HTTP服务器之前手动调用它们各自的destroy方法?还是这可能是资源实例管理中的错误?的Grizzly服务器?

使用的版本是:

  • jersey-container-grizzly2-http:2.27
  • grizzly-http-server:2.4.0(具有上述依赖性)

这是代码的精简版本:

public class ServerSentEventResource {
    @Context
    private Sse sse;
    private volatile SseBroadcaster broadcaster;
    private final Timer timer = new Timer();

    @PostConstruct
    public void init() {
        broadcaster = sse.newBroadcaster();
        final TimerTask task = new TimerTask() {
            // ...
        };
        timer.scheduleAtFixedRate(task, 0, 1000);
    }

    @PreDestroy
    public void destroy() {
        timer.cancel();
        broadcaster.close();
    }

    @GET
    @Produces(SseFeature.SERVER_SENT_EVENTS)
    public void get(@Context final SseEventSink eventSink) {
        broadcaster.register(eventSink);
    }
}

public static void main(final String[] args) {
    ResourceConfig resourceConfig = new ResourceConfig();
    resourceConfig.register(ServerSentEventResource.class);

    HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create("0.0.0.0:8888"), resourceConfig);
    System.in.read();
    server.shutdownNow();

    // At this point there is still the resource instance around, keeping the timer running, thus keeping the JVM running :(
}

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。在实际关闭服务器之前,我可以通过删除默认的网络侦听器来解决此问题。

key