How to Integrate SDS via Spring AOP: Architecture, Principles, and Limitations

Integrating SDS via Spring AOP relies on a method-level Aspect that intercepts @SdsDowngradeMethod annotations to check real-time degradation decisions, execute fallbacks, and report statistics, but it only works on Spring-managed beans and cannot intercept self-invoked or final methods.

The didi/sds repository provides a lightweight Service Degrade System (SDS) that integrates with Spring Boot applications through Spring AOP. By leveraging the @SdsDowngradeMethod annotation and the SdsPointAspect, developers can add circuit-breaker-like degradation logic without modifying business code. Understanding the architectural principles and inherent limitations of this Spring AOP integration is essential for reliable production deployments.

How the SDS Spring AOP Integration Works

The integration consists of three main components that work together to provide seamless degradation capabilities.

Auto-Configuration and Client Setup

The SdsAutoConfiguration class reads SdsProperties and registers a singleton SdsClient bean in the Spring context. This client holds configuration details such as the application group name, application name, and SDS server addresses. Located at sds-extension/sds-spring-boot/sds-spring-boot-autoconfigure/src/main/java/com/didiglobal/sds/extension/spring/boot/autoconfigure/SdsAutoConfiguration.java, this auto-configuration ensures the rest of the system can obtain a ready-to-use client without manual bean definition.

Method-Level Interception

The core logic resides in SdsPointAspect, found at sds-extension/sds-aspectj/src/main/java/com/didiglobal/sds/aspectj/SdsPointAspect.java. This Aspect implements an around advice that processes every method annotated with @SdsDowngradeMethod. When a Spring-managed bean invokes an annotated method, the Aspect executes the following sequence:

  1. Entry – Retrieves the point name from the annotation.
  2. Decision – Calls SdsClient.shouldDowngrade(point) to check the current degradation status. If true, an SdsException is thrown immediately, skipping the original business logic.
  3. Fallback resolution – If the annotation supplies a fallback name, the Aspect looks for a method with that name in the same class. It accepts either the exact same signature or the same parameters plus a trailing SdsException.
  4. Admin-driven return value – When no fallback is defined, the Aspect queries SdsDowngradeReturnValueService for a pre-configured return value stored in the SDS admin console.
  5. Exception reporting – Any uncaught exception is reported to the client via sdsClient.exceptionSign(point, throwable).
  6. Finally blocksdsClient.downgradeFinally(point) ensures counters are updated regardless of the outcome.

All interception is performed by Spring’s proxy-based AOP mechanism, which requires the target class to be a Spring bean proxied via JDK dynamic proxy or CGLIB.

Optional Controller Logging

For administrative visibility, the SdsAspectAop class at sds-admin/src/main/java/com/didiglobal/sds/admin/aop/SdsAspectAop.java provides additional AOP advice. This Aspect logs every controller entry and exit, distinguishing heartbeat endpoints from business calls, enabling the SDS admin UI to display request/response data without touching core business code.

Core Principles of the SDS AOP Architecture

Understanding the design philosophy behind the SDS Spring integration helps developers apply it effectively.

  • Annotation-driven degradation – Developers place @SdsDowngradeMethod(point = "...") on business methods. The annotation carries the point identifier and an optional fallback method name, keeping business code clean.
  • Centralized client management – The SdsClient created by SdsAutoConfiguration manages configuration and communicates with the SDS server to obtain real-time degradation decisions. This centralization ensures consistent behavior across the application.
  • Separation of concerns – Degradation logic lives entirely inside the Aspect. Fallback methods are regular Java methods within the same class, making the fallback path explicit, testable, and maintainable.
  • Runtime configurability – The SDS admin console can change degradation status or supply static return values without redeploying services. The Aspect queries SdsDowngradeReturnValueService on each call to reflect these changes immediately.
  • Cross-cutting observability – The optional SdsAspectAop demonstrates how to add logging and metrics without polluting business logic, leveraging Spring AOP's ability to handle cross-cutting concerns.

Limitations When Integrating SDS via Spring AOP

While powerful, the Spring AOP integration has specific constraints that affect where and how you can apply degradation.

Spring Bean and Proxy Constraints

Only methods on Spring-managed beans are intercepted. Direct calls to non-bean objects bypass the Aspect entirely. Additionally, self-invoked methods within the same bean circumvent the proxy, meaning internal calls to @SdsDowngradeMethod annotated methods will not trigger degradation checks. Final classes or final methods also cannot be proxied by CGLIB, rendering them incompatible with the @SdsDowngradeMethod annotation.

AspectJ Weaving Limitations

The repository provides a pure Spring AOP implementation using SdsPointAspect. If your architecture requires compile-time or load-time weaving to intercept non-bean calls or private methods, you must switch to full AspectJ and add the appropriate Weaver dependencies. The standard SDS Spring Boot starter does not include these capabilities.

Fallback Method Signature Rigidity

The fallback method must reside in the same class as the original method. The Aspect searches for a method matching either the original signature exactly, or the original signature with an additional trailing SdsException parameter. Mismatched signatures cause the Aspect to log a warning and return null rather than executing the intended fallback logic.

Performance and Operational Constraints

  • Latency overhead – The around advice adds a small amount of latency for each annotated call due to proxy dispatch, decision checks, and possible fallback reflection. Critical high-throughput paths should be profiled to ensure acceptable performance.
  • Configuration immutability – The SdsClient caches the server list and metadata. Changing properties at runtime (such as server addresses) requires an application restart or custom re-initialization logic.
  • Exception handling requirements – If both a fallback and an admin-provided return value are absent, the Aspect re-throws the original SdsException. Application code must be prepared to handle this specific exception type to avoid unexpected crashes during degradation events.

Practical Implementation Guide

1. Configure SDS Properties

Add the following to your application.yml:

sds:
  appGroupName: myAppGroup
  appName: myService
  serverAddrList: http://sds-server:8080

2. Enable Auto-Configuration

Include the SDS Spring Boot starter on your classpath. Spring Boot automatically loads SdsAutoConfiguration, which registers the SdsClient bean:

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

3. Annotate Business Methods with Fallback

Create a service with degradation protection:

import com.didiglobal.sds.client.annotation.SdsDowngradeMethod;
import com.didiglobal.sds.client.exception.SdsException;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private static final String CREATE_ORDER_POINT = "createOrder";

    @SdsDowngradeMethod(point = CREATE_ORDER_POINT, fallback = "createOrderFallback")
    public Order createOrder(OrderRequest request) {
        // normal business logic
        return new Order();
    }

    public Order createOrderFallback(OrderRequest request, SdsException ex) {
        // graceful degradation logic
        return Order.degradedPlaceholder();
    }
}

The SdsPointAspect intercepts createOrder, checks the SDS server, and either executes the method, calls createOrderFallback, or throws SdsException.

4. Alternative Fallback Signatures

You can also define a fallback without the exception parameter:

@SdsDowngradeMethod(point = CREATE_ORDER_POINT, fallback = "simpleFallback")
public Order createOrder(OrderRequest request) {
    return new Order();
}

public Order simpleFallback(OrderRequest request) {
    return Order.degradedPlaceholder();
}

The Aspect first searches for the signature with the trailing SdsException; if not found, it falls back to the plain signature.

5. Add Controller Logging (Optional)

To enable request/response logging for the SDS admin UI, include the sds-admin module. The SdsAspectAop automatically logs controller methods:

@RestController
public class HeartbeatController {
    @GetMapping("/heartbeat")
    public HeartbeatResponse heartbeat() {
        return new HeartbeatResponse();
    }
}

No additional code is required; the Aspect logs request arguments (excluding ServletResponse) and JSON-serializes the response.

Summary

  • Integrating SDS via Spring AOP requires Spring-managed beans and relies on SdsPointAspect to intercept @SdsDowngradeMethod annotations.
  • The SdsAutoConfiguration class bootstraps the system by creating a centralized SdsClient from SdsProperties.
  • Degradation decisions, fallback execution, and statistics reporting happen automatically through around advice.
  • Limitations include: no support for final methods, inability to intercept self-invoked methods, rigid fallback signature requirements, and runtime configuration caching that requires restart to update.
  • For non-bean interception or private method weaving, you must migrate from Spring AOP to full AspectJ weaving.

Frequently Asked Questions

Can I use SDS with non-Spring beans or static methods?

No. The standard SDS Spring AOP integration only works on Spring-managed beans because it relies on Spring's proxy-based AOP mechanism. Static methods, private methods, and calls on non-bean objects bypass the SdsPointAspect. To intercept such calls, you would need to switch to AspectJ compile-time or load-time weaving and add the necessary Weaver dependencies.

What happens if my fallback method signature does not match?

If the Aspect cannot find a fallback method matching either the original signature or the original signature plus a trailing SdsException, it logs a warning and returns null. The fallback must also reside in the same class as the annotated method. Ensure your fallback method is public and follows these signature rules to guarantee execution during degradation events.

Does SDS Spring AOP support final classes or methods?

No. Because Spring AOP uses either JDK dynamic proxies (for interfaces) or CGLIB (for classes), it cannot proxy final classes or final methods. Annotating a final method with @SdsDowngradeMethod will have no effect, as the proxy cannot override the method to insert the around advice. Remove the final modifier or consider refactoring to use interface-based proxies.

How should I handle the SdsException thrown during degradation?

If no fallback is defined and no admin-configured return value exists, the SdsPointAspect throws SdsException when degradation is triggered. Your application should catch this exception in upstream layers (such as controllers or global exception handlers) and convert it to an appropriate user-facing response, such as an HTTP 503 status code or a cached result. Do not let SdsException propagate unhandled to end users.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →