Mikroservices auf Java: Architektur und Praxis von A bis Z
\n\nDie Microservice-Architektur (MSA) ist zum De-facto-Standard für die Entwicklung moderner skalierbarer Anwendungen geworden. Im Gegensatz zum Monolithen, bei dem der gesamte Code ein einziger großer Prozess ist, unterteilen Mikroservices das System in kleine, unabhängig bereitstellbare Dienste. In diesem Artikel werden wir untersuchen, wie man Mikroservices auf Java mit gängigen Technologien entwirft und implementiert: Spring Boot, Docker, Kafka und Spring Cloud. Sie erhalten fertige Rezepte und Codebeispiele.
\n\n1. Grundlagen der Mikroservices-Architektur auf Java
\n\nBevor wir Code schreiben, ist es wichtig, die Schlüsselprinzipien von MSA zu verstehen:
\n- \n
- Einzelverantwortung (Single Responsibility) – jeder Dienst ist für eine Geschäftsfunktion verantwortlich (z. B. Bestelldienst, Benutzerdienst). \n
- Unabhängige Bereitstellung – Sie können einen Dienst aktualisieren, ohne das gesamte System neu zu starten. \n
- Dezentrale Datenverwaltung – jeder Dienst hat seine eigene Datenbank (Database per Service). \n
- Lockere Kopplung – Dienste kommunizieren über leichtgewichtige Protokolle (REST, gRPC, Nachrichtenwarteschlangen). \n
Für Java ist das wichtigste Framework Spring Boot in Verbindung mit Spring Cloud (für Service Discovery, Konfiguration, API-Gateways). Betrachten wir ein minimales Beispiel eines Mikroservices.
\n\nBeispiel: Ein einfacher REST-Dienst mit Spring Boot
\n// pom.xml (Ausschnitt der Abhängigkeiten)\n<dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-web</artifactId>\n</dependency>\n\n// UserServiceApplication.java\n@SpringBootApplication\npublic class UserServiceApplication {\n public static void main(String[] args) {\n SpringApplication.run(UserServiceApplication.class, args);\n }\n}\n\n// UserController.java\n@RestController\n@RequestMapping("/api/users")\npublic class UserController {\n\n @GetMapping("/{id}")\n public ResponseEntity<String> getUser(@PathVariable Long id) {\n // In einem echten Projekt würde hier ein Repository-Aufruf stehen\n return ResponseEntity.ok("Benutzer mit ID: " + id);\n }\n}\n\nDieser Mikroservice lauscht auf Port 8080 und antwortet auf GET-Anfragen. Um einen zweiten Dienst zu starten (z. B. Bestelldienst), erstellen Sie einfach ein weiteres Spring Boot-Projekt mit einem anderen Port (server.port=8081).
\n\n2. Praxis: Docker, Kafka und dienstübergreifende Kommunikation
\n\nIn einem realen System können Mikroservices nicht ohne Orchestrierung direkt über HTTP kommunizieren. Es werden zwei Ansätze verwendet: synchron (REST/Feign) und asynchron (Message Broker).
\n\n2.1. Containerisierung mit Docker
\nJeder Mikroservice wird in ein Docker-Image verpackt. Beispiel-Dockerfile für einen Java-Dienst:
\nFROM openjdk:17-jdk-slim\nCOPY target/user-service-0.0.1-SNAPSHOT.jar app.jar\nEXPOSE 8080\nENTRYPOINT ["java", "-jar", "/app.jar"]\nVerwenden Sie dann docker-compose.yml, um alle Dienste gleichzeitig zu starten:
version: '3.8'\nservices:\n user-service:\n build: ./user-service\n ports:\n - "8080:8080"\n order-service:\n build: ./order-service\n ports:\n - "8081:8081"\n postgres:\n image: postgres:15\n environment:\n POSTGRES_DB: mydb\n POSTGRES_USER: user\n POSTGRES_PASSWORD: pass\n\n2.2. Asynchrone Kommunikation über Apache Kafka
\nWenn ein Dienst andere Dienste über ein Ereignis benachrichtigen muss (z. B. "Bestellung erstellt"), ist Kafka die bessere Wahl. Dies entkoppelt die Dienste und erhöht die Ausfallsicherheit.
\n\nBeispiel eines Producers (Order Service sendet ein Ereignis):
\n// KafkaProducerConfig.java\n@Configuration\npublic class KafkaProducerConfig {\n @Bean\n public ProducerFactory<String, String> producerFactory() {\n Map<String, Object> props = new Ha