这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spring-boot-modules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
<module>spring-boot-3-4</module>
<module>spring-boot-4</module>
<module>spring-boot-resilience4j</module>
<module>spring-boot-retries</module>
<module>spring-boot-properties</module>
<module>spring-boot-properties-2</module>
<module>spring-boot-properties-3</module>
Expand Down
64 changes: 64 additions & 0 deletions spring-boot-modules/spring-boot-retries/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring-boot-retries</groupId>
<artifactId>spring-boot-retries</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>spring-boot-retries</name>

<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5</artifactId>
<version>5.2.1</version>
</dependency>

<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.baeldung.retries;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RetrylogicApplication {

public static void main(String[] args) {
SpringApplication.run(RetrylogicApplication.class, args);
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.baeldung.retries.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.web.client.RestTemplate;

@Configuration
@EnableRetry
public class RestTemplateConfig {

@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000);
factory.setConnectionRequestTimeout(5000);

return new RestTemplate(factory);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.baeldung.retries.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

@Configuration
public class RetryTemplateConfig {

@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();

FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(2000);

SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(3);

retryTemplate.setBackOffPolicy(backOffPolicy);
retryTemplate.setRetryPolicy(retryPolicy);

return retryTemplate;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.baeldung.retries.controller;

import com.baeldung.retries.service.ExponentialBackoffRetryService;
import com.baeldung.retries.service.RestTemplateRetryService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class RetryController {

private final RestTemplateRetryService retryService;
private final ExponentialBackoffRetryService exponentialService;

public RetryController(RestTemplateRetryService retryService,
ExponentialBackoffRetryService exponentialService) {
this.retryService = retryService;
this.exponentialService = exponentialService;
}

@GetMapping("/fetch-with-retry")
public ResponseEntity<String> fetchWithRetry(@RequestParam String url) {
try {
String result = retryService.makeRequestWithRetry(url);
return ResponseEntity.ok(result);
} catch (RuntimeException e) {
return ResponseEntity.status(503)
.body("Service unavailable after retries: " + e.getMessage());
}
}

@GetMapping("/fetch-with-exponential-backoff")
public ResponseEntity<String> fetchWithExponentialBackoff(
@RequestParam String url) {
try {
String result = exponentialService
.makeRequestWithExponentialBackoff(url);
return ResponseEntity.ok(result);
} catch (RuntimeException e) {
return ResponseEntity.status(503)
.body("Service unavailable after retries: " + e.getMessage());
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.baeldung.retries.service;

import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

@Service
public class ExponentialBackoffRetryService {

private final RestTemplate restTemplate;
private int maxRetries = 5;
private long initialDelay = 1000;

public ExponentialBackoffRetryService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public String makeRequestWithExponentialBackoff(String url) {
int attempt = 0;
while (attempt < maxRetries) {
try {
return restTemplate.getForObject(url, String.class);
} catch (ResourceAccessException e) {
attempt++;
if (attempt >= maxRetries) {
throw new RuntimeException(
"Failed after " + maxRetries + " attempts", e);
}
long delay = initialDelay * (long) Math.pow(2, attempt - 1);
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException("Retry interrupted", ie);
}
}
}
throw new RuntimeException("Unexpected error in retry logic");
}

public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}

public void setInitialDelay(long initialDelay) {
this.initialDelay = initialDelay;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.baeldung.retries.service;

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.annotation.Recover;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;


@Service
public class RestClientService {

private final RestTemplate restTemplate;

public RestClientService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Retryable(
retryFor = {ResourceAccessException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 2000))
public String fetchData(String url) {
return restTemplate.getForObject(url, String.class);
}

@Recover
public String recover(ResourceAccessException e, String url) {
return "Fallback response after all retries failed for: " + url;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.baeldung.retries.service;

import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

@Service
public class RestTemplateRetryService {

private final RestTemplate restTemplate;
private int maxRetries = 3;
private long retryDelay = 2000;

public RestTemplateRetryService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public String makeRequestWithRetry(String url) {
int attempt = 0;
while (attempt < maxRetries) {
try {
return restTemplate.getForObject(url, String.class);
} catch (ResourceAccessException e) {
attempt++;
if (attempt >= maxRetries) {
throw new RuntimeException(
"Failed after " + maxRetries + " attempts", e);
}
try {
Thread.sleep(retryDelay);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException("Retry interrupted", ie);
}
}
}
throw new RuntimeException("Unexpected error in retry logic");
}

public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}

public void setRetryDelay(long retryDelay) {
this.retryDelay = retryDelay;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.baeldung.retries.service;

import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class RetryTemplateService {

private final RestTemplate restTemplate;
private final RetryTemplate retryTemplate;

public RetryTemplateService(RestTemplate restTemplate, RetryTemplate retryTemplate) {
this.restTemplate = restTemplate;
this.retryTemplate = retryTemplate;
}

public String fetchDataWithRetryTemplate(String url) {
return retryTemplate.execute(context -> {
return restTemplate.getForObject(url, String.class);
}, context -> {
return "Fallback response";
});
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
spring.application.name=retrylogic
server.port=8080
logging.level.org.springframework.web.client=DEBUG
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.baeldung.retries.retrylogic;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class RetrylogicApplicationTests {

@Test
void contextLoads() {
}

}

Loading