search
HomeJavajavaTutorialAdvanced Error Handling in Spring Boot Microservices

Advanced Error Handling in Spring Boot Microservices

In complex microservices, advanced error handling goes beyond simple exception logging. Effective error handling is crucial for reliability, scalability, and maintaining good user experience. This article will cover advanced techniques for error handling in Spring Boot microservices, focusing on strategies for managing errors in distributed systems, handling retries, creating custom error responses, and logging errors in a way that facilitates debugging.

1. Basic Error Handling in Spring Boot

Let’s start with a foundational error handling approach in Spring Boot to set up a baseline.

1.1 Using @ControllerAdvice and @ExceptionHandler

Spring Boot provides a global exception handler with @ControllerAdvice and @ExceptionHandler. This setup lets us handle exceptions across all controllers in one place.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<errorresponse> handleResourceNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
        return new ResponseEntity(error, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<errorresponse> handleGeneralException(Exception ex) {
        ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", "An unexpected error occurred.");
        return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
</errorresponse></errorresponse>

Here, ErrorResponse is a custom error model:

public class ErrorResponse {
    private String code;
    private String message;

    // Constructors, Getters, and Setters
}

1.2 Returning Consistent Error Responses

Ensuring all exceptions return a consistent error response format (e.g., ErrorResponse) helps clients interpret errors correctly.


2. Advanced Techniques for Error Handling

2.1 Centralized Logging and Tracking with Error IDs

Assigning a unique error ID to each exception helps track specific errors across services. This ID can also be logged alongside exception details for easier debugging.

@ExceptionHandler(Exception.class)
public ResponseEntity<errorresponse> handleGeneralException(Exception ex) {
    String errorId = UUID.randomUUID().toString();
    log.error("Error ID: {}, Message: {}", errorId, ex.getMessage(), ex);

    ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", 
                                             "An unexpected error occurred. Reference ID: " + errorId);
    return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
</errorresponse>

Clients receive an error response containing errorId, which they can report back to support, linking them directly to the detailed logs.

2.2 Adding Retry Logic for Transient Errors

In distributed systems, transient issues (like network timeouts) can be resolved with a retry. Use Spring’s @Retryable for retry logic on service methods.

Setup

First, add Spring Retry dependency in your pom.xml:

<dependency>
    <groupid>org.springframework.retry</groupid>
    <artifactid>spring-retry</artifactid>
</dependency>

Then, enable Spring Retry with @EnableRetry and annotate methods that need retries.

@EnableRetry
@Service
public class ExternalService {

    @Retryable(
        value = { ResourceAccessException.class },
        maxAttempts = 3,
        backoff = @Backoff(delay = 2000))
    public String callExternalService() throws ResourceAccessException {
        // Code that calls an external service
    }

    @Recover
    public String recover(ResourceAccessException e) {
        log.error("External service call failed after retries.", e);
        return "Fallback response due to error.";
    }
}

This configuration retries the method up to 3 times, with a delay of 2 seconds between attempts. If all attempts fail, the recover method executes as a fallback.

2.3 Using Feign Client with Fallback in Microservices

For error handling in service-to-service calls, Feign provides a declarative way to set up retries and fallbacks.

Feign Configuration

Define a Feign client with fallback support:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<errorresponse> handleResourceNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
        return new ResponseEntity(error, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<errorresponse> handleGeneralException(Exception ex) {
        ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", "An unexpected error occurred.");
        return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
</errorresponse></errorresponse>

This approach ensures that if inventory-service is unavailable, the InventoryServiceFallback kicks in with a predefined response.


3. Error Logging and Observability

3.1 Centralized Logging with ELK Stack

Configure an ELK (Elasticsearch, Logstash, Kibana) stack to consolidate logs from multiple microservices. With a centralized logging system, you can easily trace issues across services and view logs with associated error IDs.

For example, configure log patterns in application.yml:

public class ErrorResponse {
    private String code;
    private String message;

    // Constructors, Getters, and Setters
}

3.2 Adding Trace IDs with Spring Cloud Sleuth

In distributed systems, tracing a single transaction across multiple services is critical. Spring Cloud Sleuth provides distributed tracing with unique trace and span IDs.

Add Spring Cloud Sleuth in your dependencies:

@ExceptionHandler(Exception.class)
public ResponseEntity<errorresponse> handleGeneralException(Exception ex) {
    String errorId = UUID.randomUUID().toString();
    log.error("Error ID: {}, Message: {}", errorId, ex.getMessage(), ex);

    ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", 
                                             "An unexpected error occurred. Reference ID: " + errorId);
    return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
</errorresponse>

4. Custom Error Handling for REST APIs

4.1 Creating Custom Exception Classes

Define custom exceptions to provide more specific error handling.

<dependency>
    <groupid>org.springframework.retry</groupid>
    <artifactid>spring-retry</artifactid>
</dependency>

4.2 Custom Error Response Structure

Customize error responses by implementing ErrorAttributes for structured and enriched error messages.

@EnableRetry
@Service
public class ExternalService {

    @Retryable(
        value = { ResourceAccessException.class },
        maxAttempts = 3,
        backoff = @Backoff(delay = 2000))
    public String callExternalService() throws ResourceAccessException {
        // Code that calls an external service
    }

    @Recover
    public String recover(ResourceAccessException e) {
        log.error("External service call failed after retries.", e);
        return "Fallback response due to error.";
    }
}

Register CustomErrorAttributes in your configuration to automatically customize all error responses.

4.3 API Error Response Standardization with Problem Details (RFC 7807)

Use the Problem Details format for a standardized API error structure. Define an error response model based on RFC 7807:

@FeignClient(name = "inventory-service", fallback = InventoryServiceFallback.class)
public interface InventoryServiceClient {
    @GetMapping("/api/inventory/{id}")
    InventoryResponse getInventory(@PathVariable("id") Long id);
}

@Component
public class InventoryServiceFallback implements InventoryServiceClient {

    @Override
    public InventoryResponse getInventory(Long id) {
        // Fallback logic, like returning cached data or an error response
        return new InventoryResponse(id, "N/A", "Fallback inventory");
    }
}

Then, return this structured response from the @ControllerAdvice methods to maintain a consistent error structure across all APIs.

logging:
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

5. Circuit Breakers for Resilience

Integrating a circuit breaker pattern protects your microservice from repeatedly calling a failing service.

Using Resilience4j Circuit Breaker
Add Resilience4j to your dependencies:

<dependency>
    <groupid>org.springframework.cloud</groupid>
    <artifactid>spring-cloud-starter-sleuth</artifactid>
</dependency>

Then, wrap a method with a circuit breaker:

public class InvalidRequestException extends RuntimeException {
    public InvalidRequestException(String message) {
        super(message);
    }
}

This setup stops calling getInventory if it fails multiple times, and inventoryFallback returns a safe response instead.


Conclusion

Advanced error handling in Spring Boot microservices includes:

Centralized error handling for consistent responses and simplified debugging.
Retries and circuit breakers for resilient service-to-service calls.
Centralized logging and traceability with tools like ELK and Sleuth.
Custom error formats with Problem Details and structured error responses.
These techniques help ensure your microservices are robust, providing consistent, traceable error responses while preventing cascading failures across services.

The above is the detailed content of Advanced Error Handling in Spring Boot Microservices. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
JVM performance vs other languagesJVM performance vs other languagesMay 14, 2025 am 12:16 AM

JVM'sperformanceiscompetitivewithotherruntimes,offeringabalanceofspeed,safety,andproductivity.1)JVMusesJITcompilationfordynamicoptimizations.2)C offersnativeperformancebutlacksJVM'ssafetyfeatures.3)Pythonisslowerbuteasiertouse.4)JavaScript'sJITisles

Java Platform Independence: Examples of useJava Platform Independence: Examples of useMay 14, 2025 am 12:14 AM

JavaachievesplatformindependencethroughtheJavaVirtualMachine(JVM),allowingcodetorunonanyplatformwithaJVM.1)Codeiscompiledintobytecode,notmachine-specificcode.2)BytecodeisinterpretedbytheJVM,enablingcross-platformexecution.3)Developersshouldtestacross

JVM Architecture: A Deep Dive into the Java Virtual MachineJVM Architecture: A Deep Dive into the Java Virtual MachineMay 14, 2025 am 12:12 AM

TheJVMisanabstractcomputingmachinecrucialforrunningJavaprogramsduetoitsplatform-independentarchitecture.Itincludes:1)ClassLoaderforloadingclasses,2)RuntimeDataAreafordatastorage,3)ExecutionEnginewithInterpreter,JITCompiler,andGarbageCollectorforbytec

JVM: Is JVM related to the OS?JVM: Is JVM related to the OS?May 14, 2025 am 12:11 AM

JVMhasacloserelationshipwiththeOSasittranslatesJavabytecodeintomachine-specificinstructions,managesmemory,andhandlesgarbagecollection.ThisrelationshipallowsJavatorunonvariousOSenvironments,butitalsopresentschallengeslikedifferentJVMbehaviorsandOS-spe

Java: Write Once, Run Anywhere (WORA) - A Deep Dive into Platform IndependenceJava: Write Once, Run Anywhere (WORA) - A Deep Dive into Platform IndependenceMay 14, 2025 am 12:05 AM

Java implementation "write once, run everywhere" is compiled into bytecode and run on a Java virtual machine (JVM). 1) Write Java code and compile it into bytecode. 2) Bytecode runs on any platform with JVM installed. 3) Use Java native interface (JNI) to handle platform-specific functions. Despite challenges such as JVM consistency and the use of platform-specific libraries, WORA greatly improves development efficiency and deployment flexibility.

Java Platform Independence: Compatibility with different OSJava Platform Independence: Compatibility with different OSMay 13, 2025 am 12:11 AM

JavaachievesplatformindependencethroughtheJavaVirtualMachine(JVM),allowingcodetorunondifferentoperatingsystemswithoutmodification.TheJVMcompilesJavacodeintoplatform-independentbytecode,whichittheninterpretsandexecutesonthespecificOS,abstractingawayOS

What features make java still powerfulWhat features make java still powerfulMay 13, 2025 am 12:05 AM

Javaispowerfulduetoitsplatformindependence,object-orientednature,richstandardlibrary,performancecapabilities,andstrongsecurityfeatures.1)PlatformindependenceallowsapplicationstorunonanydevicesupportingJava.2)Object-orientedprogrammingpromotesmodulara

Top Java Features: A Comprehensive Guide for DevelopersTop Java Features: A Comprehensive Guide for DevelopersMay 13, 2025 am 12:04 AM

The top Java functions include: 1) object-oriented programming, supporting polymorphism, improving code flexibility and maintainability; 2) exception handling mechanism, improving code robustness through try-catch-finally blocks; 3) garbage collection, simplifying memory management; 4) generics, enhancing type safety; 5) ambda expressions and functional programming to make the code more concise and expressive; 6) rich standard libraries, providing optimized data structures and algorithms.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software