-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
Frody edited this page Sep 3, 2026
·
2 revisions
Add the starter to your pom.xml:
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-spring-boot-starter</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>This single dependency includes:
-
scopeflow-core— Core API -
scopeflow-mdc— SLF4J MDC integration -
scopeflow-spring-boot-autoconfigure— Auto-configuration - Spring Boot starter
Use individual modules:
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-core</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<!-- Optional: MDC integration -->
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-mdc</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>To align all ScopeFlow versions:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.frodygr</groupId>
<artifactId>scopeflow-bom</artifactId>
<version>0.1.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>// Spring Boot: auto-injected, just @Autowire it
@Autowired
private ScopeFlow scopeFlow;
// Non-Spring: build manually
ScopeFlow scopeFlow = ScopeFlowBuilder.create()
.propagator(new MdcPropagator(MdcKeyPolicy.allowAll()))
.build();try (Scope scope = scopeFlow.open("order.process",
Map.of("order.id", "ORD-123", "customer.id", "CUST-456"))) {
log.info("Processing order");
// MDC automatically contains: order.id=ORD-123, customer.id=CUST-456
// Enrich the scope dynamically
scope.put("status", "VALIDATED");
processPayment();
shipOrder();
}
// Scope closed — MDC cleaned up automaticallypublic void processPayment() {
// Access the current context from anywhere in the call stack
String orderId = scopeFlow.currentContext()
.get("order.id")
.orElse("unknown");
log.info("Processing payment for order {}", orderId);
// Log output: [order.id=ORD-123] Processing payment for order ORD-123
}// Wrap a Runnable — context propagates to the new thread
executor.submit(scopeFlow.wrap(() -> {
log.info("Async work");
// MDC still has order.id=ORD-123!
}));
// Or wrap the entire executor
ExecutorService wrapped = scopeFlow.wrapExecutor(existingExecutor);
wrapped.submit(() -> {
// Context automatically available here too
});try (Scope httpScope = scopeFlow.open("http.request",
Map.of("request.id", "abc-123"))) {
try (Scope dbScope = scopeFlow.open("db.query",
Map.of("query.table", "orders"))) {
// Both request.id and query.table are in context and MDC
log.info("Executing query");
}
// query.table is gone, request.id still here
log.info("Continuing request");
}
// Everything cleaned upWith the starter, ScopeFlow works out of the box:
@RestController
public class OrderController {
@Autowired
private ScopeFlow scopeFlow;
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// The MVC interceptor already opened a scope with:
// request.id=<UUID or X-Request-ID header>
// http.method=POST
// http.path=/orders
try (Scope scope = scopeFlow.open("order.create")
.put("customer.id", request.customerId())) {
log.info("Creating order");
// Log: [req=abc-123] [cust=CUST-1] Creating order
return orderService.create(request);
}
}
}<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [req=%X{request.id:-}] [cust=%X{customer.id:-}] %logger{24} - %msg%n</pattern>14:23:01.123 [virtual-1] INFO [req=abc-123] [cust=CUST-1] OrderController - Creating order
14:23:01.145 [virtual-1] INFO [req=abc-123] [cust=CUST-1] PaymentService - Processing payment
14:23:01.200 [virtual-2] INFO [req=abc-123] [cust=CUST-1] NotificationService - [ASYNC] Sending notification
Notice how request.id and customer.id appear in all log lines, even on different threads!
ScopeFlow • Distributed Context & Tracing Propagation • Licensed under Apache-2.0