RU | EN | DE

1. RestTemplate (Synchroner Client)

📌 Alt, aber noch verwendet. In Spring 6 als veraltet (deprecated) angesehen, aber es ist wichtig, ihn zu kennen.
📄 Bean-Konfiguration:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(3))
                .setReadTimeout(Duration.ofSeconds(5))
                .build();
    }
}

📄 Verwendungsbeispiele:

@Service
@RequiredArgsConstructor
public class WeatherService {
    private final RestTemplate restTemplate;
    public WeatherDto getWeather(String city) {
        String url = "https://api.weather.com/city/" + city;
        return restTemplate.getForObject(url, WeatherDto.class);
    }
    public void createUser(UserDto user) {
        restTemplate.postForEntity("http://localhost:8080/api/users", user, Void.class);
    }
}

2. WebClient (Reactive Client)

📌 Moderne Alternative zu RestTemplate. Unterstützt Asynchronität und Reaktivität.
📄 Bean-Konfiguration:

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder.baseUrl("https://api.weather.com")
                       .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                       .build();
    }
}

📄 Verwendung:

@Service
@RequiredArgsConstructor
public class WeatherService {
    private final WebClient webClient;
    public Mono<WeatherDto> getWeather(String city) {
        return webClient.get()
                       .uri("/city/{city}", city)
                       .retrieve()
                       .bodyToMono(WeatherDto.class);
    }
 
    public Flux<UserDto> getUsers() {
        return webClient.get()
                       .uri("/api/users")
                       .retrieve()
                       .bodyToFlux(UserDto.class);
    }
}
 
📌 Mono<T> = a single object (analogous to Optional),
Flux<T> = a stream of objects (like List).

3. OpenFeign (Declarative Client)

📌 Wenn du Microservices hast → die beste Wahl. Es ist nicht nötig, RestTemplate oder WebClient manuell zu schreiben.

📄 Abhängigkeit:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

📄 Integration:

@SpringBootApplication
@EnableFeignClients
public class DemoApplication {}

📄 Schnittstellen-Client:

@FeignClient(name = "userClient", url = "http://localhost:8080/api/users")
public interface UserClient {
    @GetMapping("/{id}")
    UserDto getUser(@PathVariable Long id);
    @PostMapping
    UserDto createUser(@RequestBody UserDto dto);
}

📄 Verwendung:

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserClient client;
    public UserDto get(Long id) {
        return client.getUser(id);
    }
}

4. Retry & Timeout (Resilience4j)

📌 Manchmal schlägt eine externe API fehl → du musst den Versuch wiederholen oder die Wartezeit begrenzen.

📄 Abhängigkeit:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>

📄 Konfiguration:

resilience4j.retry:
    instances:
        apiRetry:
            maxAttempts: 3
            waitDuration: 2s

📄 Verwendung:

@Service
public class ExternalService {
    @Retry(name = "apiRetry")
    public String callApi() {
        if (Math.random() > 0.7) {
            return "Success!";
        }
        throw new RuntimeException("API failed");
    }
}

5. Circuit Breaker (Fuse)

📌 Um zu verhindern, dass der Dienst mit ständigen Anfragen überlastet wird, wenn er bereits fehlschlägt.

📄 Konfiguration:

resilience4j.circuitbreaker:
    instances:
        apiBreaker:
            failureRateThreshold: 50
            waitDurationInOpenState: 10s
            slidingWindowSize: 10

📄 Verwendung:

@Service
public class ExternalService {
    @CircuitBreaker(name = "apiBreaker", fallbackMethod = "fallback")
    public String callApi() {
        throw new RuntimeException("API error");
    }
    public String fallback(Throwable t) {
        return "Fallback response";
    }
}

6. Async API calls (Parallel requests)

Completable Future:

@Async
public CompletableFuture<UserDto> fetchUser(Long id) {
    return CompletableFuture.supplyAsync(() -> client.getUser(id));
}

WebClient:

Flux<UserDto> users = webClient.get()
    .uri("/api/users")
    .retrieve()
    .bodyToFlux(UserDto.class);

7. Bewährte Vorgehensweisen

  • ✅ Für synchrone APIsRestTemplate (veraltet, aber noch anzutreffen).
  • ✅ Für asynchrone/reaktive DiensteWebClient.
  • ✅ Für MicroservicesFeign.
  • Retry, Timeout, Circuit Breaker mit Resilience4j hinzufügen.
  • ✅ Externe Aufrufe niemals ohne Timeouts durchführen.
  • ✅ Alle Anfragen/Antworten protokollieren (Spring Boot Sleuth oder eigener LoggingInterceptor).