Einleitung: Warum WebSocket der Standard für Echtzeitanwendungen in Java ist
Moderne Webanwendungen erfordern einen sofortigen Datenaustausch zwischen Client und Server. Das traditionelle HTTP-Protokoll, basierend auf dem "Anfrage-Antwort"-Modell, ist für Aufgaben, bei denen minimale Latenz entscheidend ist, schlecht geeignet: Online-Chats, Aktienkurse, Multiplayer-Spiele oder Echtzeit-Überwachungs-Dashboards.
Das WebSocket-Protokoll löst dieses Problem, indem es eine persistente bidirektionale Verbindung zwischen Client und Server herstellt. Nach dem anfänglichen HTTP-Handshake wird die Verbindung auf WebSocket "upgegradet", und Daten werden in Form von Frames ohne zusätzliche Header übertragen. Java bietet dank seiner leistungsstarken Standardbibliothek und Frameworks hervorragende Werkzeuge für die Arbeit mit WebSocket.
In diesem Artikel werden wir uns ansehen, wie man eine vollwertige Echtzeitanwendung in Java mit der Jakarta WebSocket API (ehemals Java EE WebSocket) erstellt. Sie erfahren mehr über Serverkonfiguration, Nachrichtenverarbeitung, Sitzungsverwaltung und typische Architekturlösungen.
Grundlagen von WebSocket in Java: Jakarta WebSocket API
Ab Java EE 7 (Jakarta EE) wurde JSR 356 — die Java API für WebSocket — zur Standardplattform hinzugefügt. Das bedeutet, dass Sie zum Erstellen eines WebSocket-Servers keine Drittanbieter-Bibliotheken einbinden müssen — lediglich einen Servlet-Container, der Jakarta EE unterstützt (z. B. Apache Tomcat 9+, Jetty 10+, WildFly).
Erstellen eines WebSocket-Endpunkts
Das Hauptelement ist eine Endpunktklasse, die mit @ServerEndpoint annotiert ist. Darin definieren wir Methoden, die bei Verbindungsaufbau, Nachrichtenempfang, Fehler oder Verbindungsschließung aufgerufen werden.
import jakarta.websocket.*;import jakarta.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/chat")public class ChatEndpoint {
private static final Set<Session> sessions = new CopyOnWriteArraySet<>();
@OnOpen public void onOpen(Session session) { sessions.add(session); broadcast("Benutzer verbunden. Gesamt: " + sessions.size()); }
@OnMessage public void onMessage(String message, Session session) { broadcast("[" + session.getId() + "]: " + message); }
@OnClose public void onClose(Session session) { sessions.remove(session); broadcast("Benutzer getrennt. Verbleibend: " + sessions.size()); }
@OnError public void onError(Session session, Throwable throwable) { System.err.println("Fehler in Sitzung " + session.getId() + ": " + throwable.getMessage()); }
private void broadcast(String message) { for (Session s : sessions) { if (s.isOpen()) { try { s.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } }}In diesem Beispiel:
@ServerEndpoint("/chat")— gibt an, dass der Endpunkt unter dem relativen Pfad/chatverfügbar ist.CopyOnWriteArraySet— eine threadsichere Sammlung zum Speichern aktiver Sitzungen.@OnOpen— wird aufgerufen, wenn eine Verbindung hergestellt wird.@OnMessage— wird aufgerufen, wenn eine Textnachricht empfangen wird.@OnClose— wird aufgerufen, wenn eine Verbindung geschlossen wird.@OnError— Fehlerbehandlung.
Clientseitiges JavaScript
Zum Testen des Servers reicht eine einfache HTML-Datei mit JavaScript aus:
<!DOCTYPE html><html><head> <title>WebSocket Chat</title></head><body> <div id="messages"></div> <input type="text" i