Я использую простой HTTP-сервер Джерси / Гризли с ресурсом для обработки отправленных сервером событий .
Этот ресурс должен вручную позаботиться об экземпляре Timer
, чтобы отправить некоторые данные поддержки активности всем подключенным клиентам SSE, поэтому я использую аннотации @PostConstruct
и @PreDestroy
для создания и отмены этого таймера (и его фона). нить).
Приложение представляет собой простое консольное приложение, не встроенное ни в одну контейнерную среду, например Tomcat. После запуска веб-сервера он ожидает простой System.in.read()
и снова выключает сервер, вызывая shutdownNow () на экземпляре сервера Grizzly HTTP.
При подключении к ресурсу SSE создается экземпляр класса ресурса и запускается таймер. После отключения от сервера, после небольшой задержки ресурс снова уничтожается и все в порядке.
Но из-за характера ресурса SSE клиент может быть подключен бесконечно, что также обеспечивает внутреннюю поддержку экземпляра ресурса.
Если я сейчас попытаюсь выключить сервер, вызвав shutdownNow()
, пока клиент подключен, экземпляр сервера корректно завершает работу, но не вызывает никаких методов @PreDestroy
активных ресурсов. Это приводит к тому, что мой ресурс с экземпляром Timer
остается на месте, и поскольку таймер все еще активен, это, в свою очередь, поддерживает выполнение процесса Java, даже если сервер HTTP уже выключен.
Есть ли способ получить все активные в данный момент экземпляры ресурса, чтобы я мог вручную вызвать их соответствующий метод уничтожения перед выключением HTTP-сервера? Или это может быть ошибка в управлении экземпляром ресурса сервер Гризли?
Используются следующие версии:
- 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 :(
}