-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
This guide covers dependency installation, bootstrapping, and basic usage patterns for Spring Boot and standalone Java applications.
ScopeFlow artifacts are hosted on Maven Central under the group io.github.frodygr.
Add the production starter to your pom.xml:
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-spring-boot-starter</artifactId>
<version>1.0.2</version>
</dependency>This dependency transitively bundles:
-
scopeflow-core: The core execution engine, immutableScopeContext, and lifecycle manager. -
scopeflow-mdc: SLF4J MDC bridge with stack unwinding and key policies. -
scopeflow-spring-boot-autoconfigure: Spring Boot 3 auto-configuration beans.
For Gradle (Kotlin DSL):
implementation("io.github.frodygr:scopeflow-spring-boot-starter:1.0.2")In microservices or libraries that do not use Spring Boot, declare only the specific modules required:
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-core</artifactId>
<version>1.0.2</version>
</dependency>
<!-- Optional: SLF4J MDC integration -->
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-mdc</artifactId>
<version>1.0.2</version>
</dependency>To manage versions consistently across multi-module projects, import the ScopeFlow BOM:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-bom</artifactId>
<version>1.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>In Spring Boot, a singleton ScopeFlow bean is automatically configured and available for injection:
@Autowired
private ScopeFlow scopeFlow;In standalone applications, configure an instance using ScopeFlowBuilder:
ScopeFlow scopeFlow = ScopeFlowBuilder.create()
.propagator(new MdcPropagator(MdcKeyPolicy.allowAll()))
.build();Enclose technical or business operations in a standard try-with-resources block:
try (Scope scope = scopeFlow.open("order.process", Map.of(
"order.id", "ORD-123",
"customer.id", "CUST-456"
))) {
log.info("Processing incoming order");
// MDC bindings active: [order.id=ORD-123 customer.id=CUST-456]
// Mutate the local scope dynamically if needed:
scope.put("order.status", "VALIDATED");
processPayment();
shipOrder();
}
// Upon exit, previous thread context is restored automatically.Any component down the synchronous call stack can access the ambient context without passing maps through method signatures:
public void processPayment() {
String orderId = scopeFlow.currentContext()
.get("order.id")
.orElse("UNKNOWN");
log.info("Initiating payment transaction for {}", orderId);
}To propagate context across thread pool or virtual thread boundaries, wrap the target task with scopeFlow.wrap():
// Propagate context to a worker Runnable
executor.submit(scopeFlow.wrap(() -> {
log.info("Executing async task");
// MDC continues to contain order.id=ORD-123
}));
// Or wrap an entire ExecutorService:
ExecutorService wrappedExecutor = scopeFlow.wrapExecutor(existingExecutor);
wrappedExecutor.submit(() -> {
log.info("Ambient context restored on worker thread");
});Nested scopes isolate their additions while preserving parent state:
try (Scope httpScope = scopeFlow.open("http.request", Map.of("request.id", "req-987"))) {
try (Scope dbScope = scopeFlow.open("db.query", Map.of("db.table", "orders"))) {
// Active context: request.id=req-987, db.table=orders
log.info("Querying orders table");
}
// db.table is popped from stack; request.id remains active
log.info("Returning HTTP response");
}
// All scope state cleared from threadWhen using scopeflow-spring-boot-starter, the ScopeFlowWebMvcInterceptor automatically intercepts incoming HTTP requests:
- Extracts or generates a UUID correlation ID (
X-Request-IDorrequest.id). - Records
http.methodandhttp.path. - Binds these attributes to the executing thread before controller logic runs.
@RestController
public class OrderController {
private static final Logger log = LoggerFactory.getLogger(OrderController.class);
private final ScopeFlow scopeFlow;
private final OrderService orderService;
public OrderController(ScopeFlow scopeFlow, OrderService orderService) {
this.scopeFlow = scopeFlow;
this.orderService = orderService;
}
@PostMapping("/orders")
public OrderResponse createOrder(@RequestBody OrderRequest request) {
// Ambient scope already holds request.id, http.method, and http.path
try (Scope scope = scopeFlow.open("order.create", Map.of("customer.id", request.customerId()))) {
log.info("Processing order creation");
return orderService.create(request);
}
}
}To expose correlation keys in your application logs, reference the MDC keys in your logback.xml pattern:
<pattern>%d{ISO8601} [%thread] %-5level [req=%X{request.id:-} cust=%X{customer.id:-}] %logger{36} - %msg%n</pattern>2026-09-03T14:23:01.123 [virtual-1] INFO [req=8f9a-11 cust=C-501] OrderController - Processing order creation
2026-09-03T14:23:01.145 [virtual-1] INFO [req=8f9a-11 cust=C-501] OrderService - Validating inventory stock
2026-09-03T14:23:01.200 [virtual-4] INFO [req=8f9a-11 cust=C-501] NotificationService - Dispatching confirmation email
ScopeFlow • Distributed Context & Tracing Propagation • Licensed under Apache-2.0