WebSocket: OnClose() никогда не вызывается
Я реализую приложение с конечной точкой WebSocket. Вот какой код:
@ApplicationScoped
@ServerEndpoint(value="/socket", encoders = {MessageEncoder.class, CommandEncoder.class})
public class SocketEndpoint {
/** Default-Logger */
private final static Logger LOG = LoggerFactory.getLogger(SocketEndpoint.class);
@Inject
SessionHandler sessionHandler;
@OnOpen
public void open(Session session, EndpointConfig config) {
LOG.debug("Connected session => '{}' - '{}'", session, config);
sessionHandler.initSession(session);
}
@OnMessage
public void onMessage(Session session, String messageJson) {
// do something
}
@OnClose
public void onClose(Session session, CloseReason reason) {
LOG.debug("Closing session => '{}' - '{}'", session, reason);
sessionHandler.removeSession(session);
}
@OnError
public void onError(Session session, Throwable ex) {
LOG.error("WebSocket error => '{}'", ex.getMessage());
}
}
Один из классов кодировки выглядит следующим образом:
public class MessageEncoder implements Encoder.Text<Message> {
/** Default-Logger */
private final static Logger LOG = LoggerFactory.getLogger(MessageEncoder.class);
@Override
public void init(EndpointConfig config) {
LOG.debug("Init MessageEncoder");
}
@Override
public void destroy() {
LOG.debug("Destroy MessageEncoder");
}
@Override
public String encode(MessageE message) throws EncodeException {
return message.toString();
}
}
Открытие вызовов WebSocket SocketEndpoint.open()
, как ожидалось.
Закрытие WebSocket вызывает только MessageEncoder.destroy()
, но не SocketEndpoint.close()
.
Может ли кто-нибудь дать мне совет, что я сделал не так? Без решения я должен был бы проверить вручную, если зарегистрированные сеансы все еще живы, так как MessageEncoder.destroy()
не имеет параметров.
Спасибо заранее!
UPDATE
Просто реализована фиктивная конечная точка:
@ApplicationScoped
@ServerEndpoint("/dummy")
public class DummyEndpoint {
/** Default-Logger */
private final static Logger LOG = LoggerFactory.getLogger(DummyEndpoint.class);
@OnOpen
public void open(Session session, EndpointConfig config) {
LOG.debug("Connected session with principal => '{}'", session.getId());
}
@OnMessage
public void onMessage(Session session, String messageJson) {
LOG.debug("on message => '{}' => '{}'", session.getId(), messageJson);
}
@OnClose
public void onClose(Session session, CloseReason reason) {
LOG.debug("Closing session => '{}' - '{}'", session, reason);
}
@OnError
public void onError(Session session, Throwable ex) {
LOG.error("WebSocket error => '{}' => '{}'", session, ex.getMessage());
}
}
При использовании этой фиктивной конечной точки @OnClose
правильно вызывается. Я вижу только одно существенное отличие от класса SocketEndpoint
: DummyEndpoint
не использует классы Encoder
.
Любые подсказки?
Ответы
Ответ 1
Как уже упоминалось в комментариях, код работает отлично. Если мы начнем с этого wildfly-websocket-quickstart, добавив @OnClose
оформленный метод в ServerEndpoint
, он отлично работает, используя Wildfly 10.x и последних браузеров (например, Chrome v59.x). Пример работы ServerEndpoint здесь (для использования @Inject
не забудьте добавить beans.xml
в папку WEB-INF):
@ApplicationScoped
@ServerEndpoint(value="/shout", encoders = {MessageEncoder.class})
public class ShoutServerEndpoint {
@Inject
SessionHandler s;
@OnOpen
public void open(Session session, EndpointConfig config) throws Exception {
s.initSession(session);
}
@OnMessage
public void shout(String text, Session client) {
System.out.println("Session: " + client + " has text: " + text);
Message m = new Message();
try {
client.getBasicRemote().sendObject(m);//use the encoder to write some dummy message
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (EncodeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
client.getAsyncRemote().sendText(text.toUpperCase());
}
@OnClose
public void onClose(Session client, CloseReason reason){
System.out.println("Session " + client + " closing for " + reason);
s.destroySession(client);
}
@OnError
public void onError(Session session, Throwable ex) {
System.out.println("error: " + ex.getMessage() );
}
}
Таким образом, виновник, по-видимому, состоит в том, что существует более старая версия кода, используемого wildfly, которая не была очищена во время перераспределения webapp, например, с использованием Eclipse, в случае странного поведения стоит использовать Clean
на используемом сервере (см. этот документ Eclipse)
Если вы устанавливаете прямо с wildfly, вы можете очистить свои ресурсы, удалив все (от в этой статье):
-
/[wildfly-location]/standalone/data
-
/[wildfly-location]/standalone/deployments
-
/[wildfly-location]/standalone/tmp
Это гарантирует, что старые копии вашего кода не будут сохранены во время будущего развертывания.