Skip to content

Getting Started

Frody edited this page Sep 3, 2026 · 2 revisions

Getting Started with ScopeFlow

This guide covers dependency installation, bootstrapping, and basic usage patterns for Spring Boot and standalone Java applications.


Installation

ScopeFlow artifacts are hosted on Maven Central under the group io.github.frodygr.

Spring Boot Applications (Recommended)

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, immutable ScopeContext, 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")

Standalone Java Applications (Without Spring)

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>

Maven Bill of Materials (BOM)

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>

Quickstart

1. Bootstrapping ScopeFlow

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();

2. Defining a Context Scope

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.

3. Reading Ambient Context

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);
}

4. Cross-Thread Context Propagation

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");
});

5. Hierarchical Scoping

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 thread

Spring Boot Web MVC Correlation

When using scopeflow-spring-boot-starter, the ScopeFlowWebMvcInterceptor automatically intercepts incoming HTTP requests:

  1. Extracts or generates a UUID correlation ID (X-Request-ID or request.id).
  2. Records http.method and http.path.
  3. Binds these attributes to the executing thread before controller logic runs.

Example Controller

@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);
        }
    }
}

Logback Pattern

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>

Sample Output

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

Clone this wiki locally