WebSocket auf Java: Erstellung von Echtzeit-Anwendungen auf fortgeschrittenem Niveau
Moderne Webanwendungen erfordern zunehmend eine sofortige Datenübertragung zwischen Client und Server. Traditionelles HTTP, das auf Anfrage-Antwort basiert, ist ineffizient für Aufgaben, bei denen Latenz kritisch ist: Online-Chats, Börsenkurse, gemeinsame Dokumentenbearbeitung oder Spieleserver. Das WebSocket-Protokoll löst dieses Problem, indem es eine permanente bidirektionale Verbindung herstellt. In diesem Artikel betrachten wir fortgeschrittene Techniken für die Arbeit mit WebSocket in Java, die über grundlegende Beispiele hinausgehen.
1. Architektur einer fortgeschrittenen WebSocket-Anwendung in Java
Das grundlegende WebSocket-Beispiel in Java unter Verwendung der Annotation @ServerEndpoint ist gut zum Lernen, aber für Produktionslösungen ist eine robustere Architektur erforderlich. Betrachten wir die Schlüsselkomponenten.
1.1. Auswahl des Technologie-Stacks
Für Enterprise-Anwendungen ist der De-facto-Standard Spring Boot mit dem Modul spring-boot-starter-websocket. Es bietet Integration mit STOMP (Simple Text Oriented Messaging Protocol) – einem Subprotokoll über WebSocket, das Nachrichtenrouting, Warteschlangen und Abonnements hinzufügt.
1.2. Grundlegende WebSocket-Konfiguration in Spring Boot
Beginnen wir mit der Konfigurationsklasse:
@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override public void configureMessageBroker(MessageBrokerRegistry config) { // Eingebauter Broker für Warteschlangen /topic und /queue config.enableSimpleBroker("/topic", "/queue"); // Präfix für Nachrichten vom Client zum Server config.setApplicationDestinationPrefixes("/app"); // Präfix für benutzerspezifische Warteschlangen (Punkt-zu-Punkt) config.setUserDestinationPrefix("/user"); }
@Override public void registerStompEndpoints(StompEndpointRegistry registry) { // Endpunkt für Verbindung über SockJS (Fallback für ältere Browser) registry.addEndpoint("/ws") .setAllowedOrigins("*") .withSockJS(); }}Dieser Code konfiguriert Verbindungspunkte, Präfixe für das Routing und einen eingebauten Nachrichtenbroker. Die Verwendung von STOMP vereinfacht die Arbeit mit Abonnements und Warteschlangen erheblich.
2. Fortgeschrittene Nachrichtenverarbeitung: Vom Chat bis zu Börsendaten
Kommen wir nun zur Implementierung konkreter Szenarien. Betrachten wir drei typische Anwendungsfälle: Gruppenchat, persönliche Benachrichtigungen und Daten-Streaming.
2.1. Gruppenchat mit Nachrichtenverlauf
Ein einfacher Chat ist ein Broadcast von Nachrichten in ein Topic. Erschweren wir die Aufgabe: Fügen wir das Speichern des Verlaufs und die Filterung nach Räumen hinzu.
@Controllerpublic class ChatController {
@Autowired private ChatMessageRepository repository; // JPA Repository
@MessageMapping("/chat.sendMessage") @SendTo("/topic/chat/{roomId}") public ChatMessage sendMessage(@Payload ChatMessage message, @DestinationVariable String roomId, SimpMessageHeaderAccessor headerAccessor) { // In der Datenbank speichern message.setTimestamp(Instant.now()); repository.save(message); // Absenderinformationen aus der Sitzung hinzufügen String username = (String) headerAccessor.getSessionAttributes().get("username"); message.setSender(username); return message; }
@MessageMapping("/chat.addUser") @SendTo("/topic/chat/{roomId}") public ChatMessage addUser(@Payload ChatMessage message, @DestinationVariable String roomId, SimpMessageHeaderAccessor headerAccessor) { headerAccessor.getSessionAttributes().put("username", message.getSender()); return message; }}Hier verwenden wir