How to Integrate SDS via Java Agent: Bytecode Instrumentation Guide
The SDS Java Agent integrates Service Degradation System capabilities into your application by instrumenting bytecode at JVM startup, allowing you to protect methods with the @SdsDowngradeMethod annotation without modifying business logic.
SDS (Service Degradation System) is an open-source framework developed by Didi that provides automatic circuit breaking and degradation capabilities for Java applications. By leveraging the Java Agent mechanism, SDS can weave degradation logic into your application transparently at runtime. This article explains the instrumentation principle and step-by-step configuration for integrating SDS via Java Agent based on the actual implementation in the didi/sds repository.
How the SDS Java Agent Works
Bytecode Instrumentation Architecture
When you launch the JVM with the SDS agent attached, the entry point SdsBootStrap.premain executes before the application's main method. This method, located in sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/SdsBootStrap.java, performs three critical operations:
- Parses the agent arguments to extract configuration
- Initializes the
SdsClientsingleton for server communication - Registers the
SdsClassFileTransformerwith the JVM'sInstrumentationinstance
// From SdsBootStrap.java - registers the bytecode transformer
instrumentation.addTransformer(new SdsClassFileTransformer(param[3]));
The Class File Transformer
The SdsClassFileTransformer (defined in sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/transformer/SdsClassFileTransformer.java) intercepts every class loaded by the JVM. It filters classes based on the configured package prefixes and searches for methods annotated with @SdsDowngradeMethod.
When such a method is found, the transformer uses Javassist to inject three distinct code blocks:
| Injection Point | Purpose | Code Logic |
|---|---|---|
| Method Entry | Check degradation status | Calls SdsClient.shouldDowngrade(point); throws SdsException if degrading |
| Catch Block | Record exceptions | Invokes SdsClient.exceptionSign(point, e) for non-SDS exceptions |
| Finally Block | Update statistics | Always executes SdsClient.downgradeFinally(point) |
// Excerpt from SdsClassFileTransformer showing injection logic
declaredMethod.insertBefore(
String.format("SdsClient __sdsClient = SdsBootStrap.getClient(); " +
"if (__sdsClient != null && __sdsClient.shouldDowngrade(\"%s\")) { " +
" throw new SdsException(\"%s\", ExceptionCode.DOWNGRADE); } ",
sdsDowngradeMethod.point(), sdsDowngradeMethod.point()));
This approach ensures that degradation logic is completely non-intrusive—your business code remains clean while SDS handles protection transparently.
Configuring the SDS Java Agent
Building the Agent JAR
First, compile the bootstrap module to produce the agent JAR:
cd sds-bootstrap
mvn clean package -DskipTests
# Output: target/sds-bootstrap.jar
JVM Startup Arguments
Attach the agent to your application using the -javaagent flag. The agent requires four comma-separated parameters:
- Application group name – Logical grouping for services (e.g.,
payment-group) - Application name – Unique service identifier (e.g.,
order-service) - SDS server URL – Endpoint for fetching degradation strategies (e.g.,
http://sds-server:8080) - Package scan list – Semicolon-separated package prefixes to instrument (e.g.,
com.mycorp.service;com.mycorp.controller)
java -javaagent:/path/to/sds-bootstrap.jar=groupA,order-service,http://sds.example.com:8080,com.mycorp.service;com.mycorp.controller \
-jar myapp.jar
The SdsBootStrap.premain method splits these arguments:
String[] param = agentArgs.split(",");
// param[0] = group, param[1] = app, param[2] = url, param[3] = packages
Maven Dependencies
Add the SDS client library to your project to access annotations and exceptions:
<dependency>
<groupId>com.didiglobal.sds</groupId>
<artifactId>sds-client</artifactId>
<version>1.3.0</version>
</dependency>
This provides SdsDowngradeMethod, SdsException, and the SdsClient API.
Annotating Methods for Protection
Mark methods requiring degradation protection with @SdsDowngradeMethod. The point attribute defines the degradation strategy identifier:
import com.didiglobal.sds.client.annotation.SdsDowngradeMethod;
public class OrderService {
@SdsDowngradeMethod(point = "order.create")
public Order createOrder(Request req) {
// Business logic
return order;
}
}
Optionally specify a fallback method for graceful degradation:
@SdsDowngradeMethod(point = "order.update", fallback = "updateOrderFallback")
public void updateOrder(User user) {
// Primary logic
}
public void updateOrderFallback(User user) {
// Return cached data or queue for later processing
}
Complete Integration Example
Build and run a protected service:
# Build the agent
cd sds-bootstrap
mvn clean package
# Launch application with SDS protection
java -javaagent:target/sds-bootstrap.jar=demoGroup,demoApp,http://localhost:8080,com.example.service \
-jar ../target/my-service.jar
Application code with protection:
package com.example.service;
import com.didiglobal.sds.client.annotation.SdsDowngradeMethod;
import com.didiglobal.sds.client.exception.SdsException;
public class UserService {
@SdsDowngradeMethod(point = "user.get", fallback = "getUserFallback")
public User getUser(Long id) {
// Database call
return userRepository.findById(id);
}
public User getUserFallback(Long id) {
// Return default user or cached value
return new User(id, "Default User");
}
@SdsDowngradeMethod(point = "user.update")
public void updateUser(User user) {
// Critical update operation
userRepository.save(user);
}
}
Key Implementation Files
| File Path | Role |
|---|---|
sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/SdsBootStrap.java |
Entry point containing premain; parses agent arguments and registers the class file transformer. |
sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/transformer/SdsClassFileTransformer.java |
Implements ClassFileTransformer; scans packages and injects degradation logic into annotated methods. |
sds-client/src/main/java/com/didiglobal/sds/client/annotation/SdsDowngradeMethod.java |
Annotation definition used to mark methods requiring SDS protection. |
sds-bootstrap/pom.xml |
Maven configuration for building the sds-bootstrap.jar agent package. |
Summary
- Non-intrusive integration: The SDS Java Agent uses bytecode instrumentation to inject degradation logic without modifying source code.
- Three-point injection: The agent wraps methods with
shouldDowngradechecks at entry,exceptionSignin catch blocks, anddowngradeFinallyin finally blocks. - Four required parameters: Configure the agent with application group, application name, SDS server URL, and semicolon-separated package prefixes.
- Annotation-driven: Simply add
@SdsDowngradeMethod(point="...")to methods requiring protection, with optional fallback methods for graceful degradation. - Key classes:
SdsBootStrap.premaininitializes the agent, whileSdsClassFileTransformerperforms the bytecode manipulation using Javassist.
Frequently Asked Questions
What is the performance overhead of the SDS Java Agent?
The SDS Java Agent performs bytecode transformation only once during class loading, so there is no ongoing compilation overhead. At runtime, the injected code performs simple boolean checks via SdsClient.shouldDowngrade(), which typically involves in-memory threshold comparisons. According to the implementation in SdsClassFileTransformer, the degradation check is a lightweight client-side operation that adds minimal latency—usually microseconds—unless the SDS server itself becomes a bottleneck.
Can I use SDS without modifying my application code?
No, while the Java Agent handles the bytecode instrumentation automatically, you must still add the @SdsDowngradeMethod annotation to methods that require protection. This annotation serves as the marker for the SdsClassFileTransformer to identify which methods to instrument. Additionally, you need to include the sds-client dependency to access the annotation and exception classes. The "non-intrusive" aspect refers to not needing manual try-catch blocks or explicit client calls, not zero code changes.
How does the agent handle exceptions during degradation?
The agent injects three distinct exception handling mechanisms. First, if shouldDowngrade returns true, it throws SdsException immediately, preventing the method body from executing. Second, for business exceptions thrown during execution, the injected catch block captures them and calls exceptionSign(point, e) to record error statistics, then re-throws the original exception. Finally, the finally block ensures downgradeFinally(point) always executes to update internal counters, regardless of whether degradation occurred or an exception was thrown.
What JVM versions are supported by the SDS agent?
The SDS Java Agent uses the standard Instrumentation API and Javassist for bytecode manipulation, which are compatible with Java 8 and later versions. The premain method signature and ClassFileTransformer interface have been stable since Java 5, but the specific bytecode manipulation patterns used in SdsClassFileTransformer target Java 8+ bytecode structures. For optimal compatibility, use Java 8, 11, 17, or 21 LTS versions, ensuring you match the Javassist version defined in the sds-bootstrap/pom.xml with your target JVM.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →