Spring Boot Microservice Architektur: Von der Theorie zur Praxis

Spring Boot Microservice Architektur: Von der Theorie zur Praxis
von Zelkulon05. März 20251 min Lesezeit

Microservices mit Spring Boot strukturieren, kommunizieren lassen und absichern – ein vollständiger Praxisleitfaden mit echten Code-Beispielen und Architekturdiagrammen.

Was sind Microservices?

Eine Microservice-Architektur teilt eine Anwendung in kleine, unabhängig deploybare Dienste auf. Jeder Service ist für genau eine fachliche Domäne verantwortlich – dem Bounded Context aus dem Domain-Driven Design.

Was sind Microservices?

Jeder Service hat eine eigene Datenbank – das verhindert enge Kopplung und ermöglicht, dass jeder Service seinen eigenen Datenbanktyp wählen kann.

Projektstruktur

order-service/
├── src/main/java/com/zelkulon/order/
│   ├── OrderServiceApplication.java
│   ├── controller/
│   │   └── OrderController.java
│   ├── service/
│   │   ├── OrderService.java
│   │   └── OrderServiceImpl.java
│   ├── repository/
│   │   └── OrderRepository.java
│   ├── model/
│   │   ├── Order.java
│   │   └── OrderItem.java
│   └── dto/
│       ├── OrderRequest.java
│       └── OrderResponse.java
└── src/main/resources/
    └── application.yml

Das Domain-Modell

@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    private String customerId;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<OrderItem> items = new ArrayList<>();

    private BigDecimal totalAmount;

    @PrePersist
    void onCreate() {
        this.createdAt = LocalDateTime.now();
        this.status    = OrderStatus.PENDING;
    }
}

Service-zu-Service-Kommunikation mit Feign

Mit Spring Cloud OpenFeign verhält sich ein anderer Microservice wie ein lokales Service-Objekt:

@FeignClient(name = "product-service", url = "${services.product.url}")
public interface ProductServiceClient {

    @GetMapping("/api/products/{productId}")
    ProductDto getProduct(@PathVariable String productId);

    @PutMapping("/api/products/{productId}/stock")
    void reduceStock(@PathVariable String productId,
                     @RequestParam int quantity);
}

Circuit Breaker mit Resilience4j

Circuit Breaker verhindern Kaskadenausfälle, wenn ein Service nicht erreichbar ist:

@Service
public class OrderServiceImpl implements OrderService {

    @Override
    public OrderResponse placeOrder(OrderRequest request) {
        CircuitBreaker cb = circuitBreakerFactory.create("product-service");

        boolean available = cb.run(
            () -> checkProductAvailability(request.getItems()),
            throwable -> {
                log.warn("ProductService nicht erreichbar – Fallback aktiv");
                return false;
            }
        );

        if (!available) throw new OrderException("Produkte nicht verfügbar");
        return processOrder(request);
    }
}

Saga-Pattern für verteilte Transaktionen

Bei Microservices gibt es keine globalen Datenbank-Transaktionen. Das Saga-Pattern löst dieses Problem:

Saga-Pattern für verteilte Transaktionen

Fazit

  • Ein Service = eine fachliche Domäne – keine God-Services
  • Eigene Datenbank pro Service verhindert Datenkopplung
  • Circuit Breaker sind Pflicht für produktionsreife Systeme
  • API Gateway zentralisiert Authentifizierung und Routing
  • Saga-Pattern löst das Problem verteilter Transaktionen
Spring Boot Microservice Architektur: Von der Theorie zur Praxis