skip to content

Spring CRaC Lifecycle Integration

Spring drives its Lifecycle callbacks around a checkpoint, so pools and connections close before the snapshot and reopen on restore. This is what makes CRaC usable for a real application rather than a demo.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

What is CRaC, and what does Spring do to your beans when a checkpoint is taken and when the app is restored?

level: juniorimportance: should knowfreq 20%

answer

  1. Coordinated Restore at Checkpoint = JVM snapshot
  2. beforeCheckpoint -> stop(), afterRestore -> start()
  3. release pools/sockets before snapshot
  4. needs CRaC-enabled JDK
  5. context registered as org.crac.Resource

basics

~20 s

CRaC (Coordinated Restore at Checkpoint) snapshots a running JVM to disk and restores it later for near-instant startup. On checkpoint Spring calls stop() on its Lifecycle beans (closing pools/connections); on restore it calls start() to reopen them.

solid answer

~40 s

CRaC = Coordinated Restore at Checkpoint, an OpenJDK feature (needs a CRaC-enabled JDK) that dumps a running JVM's memory to a snapshot and later restores it, so a warmed-up app resumes in tens of milliseconds. Spring Framework 6.1+ / Spring Boot 3.2+ integrate by registering the application context as a CRaC resource. Just before the snapshot Spring drives its Lifecycle/SmartLifecycle beans through stop(), which releases things that can't survive a snapshot — JDBC connection pools, open sockets. After restore Spring calls start() again to reopen them. The idea: build once, warm up, snapshot, then restore many fast-starting instances that reconnect to fresh infrastructure.

code

java · 27 lines
java
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;

// Spring calls stop() before the checkpoint and start() after restore.
@Component
public class ExternalConnection implements SmartLifecycle {

    private volatile boolean running;
    private Client client; // holds a live socket/pool

    @Override
    public void start() {            // invoked on restore (afterRestore)
        this.client = Client.open();
        this.running = true;
    }

    @Override
    public void stop() {             // invoked on checkpoint (beforeCheckpoint)
        if (client != null) client.close();
        this.running = false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }
}

go deeper

for a junior

Know the one-liner: CRaC snapshots a running JVM; Spring stops beans before and starts them after so connections are released/reopened.

for a middle

Be able to name the two callbacks (beforeCheckpoint/afterRestore) and map them to stop()/start(), and that a CRaC JDK is required.

for a senior

Explain the coordination requirement (no open FDs allowed) and how Spring's DefaultLifecycleProcessor registers as an org.crac.Resource.

for a principal

Frame CRaC as a startup-latency alternative to native image and reason about its operational trade-offs.

**CRaC** stands for *Coordinated Restore at Checkpoint*. It is an OpenJDK project that lets you take a snapshot ("checkpoint") of a fully running JVM — its heap, threads, JIT-compiled code, everything — write it to disk, and later "restore" a brand-new process from that image. Because the JVM comes back already warmed up (classes loaded, JIT-optimized, caches populated), startup drops from seconds to tens of milliseconds. It requires a **CRaC-enabled JDK** (e.g. Azul Zulu with CRaC); a stock JDK cannot do it. **The coordination problem.** A memory snapshot cannot capture live OS resources such as open TCP sockets, file descriptors, or database connections — on restore those handles would be stale/invalid, and the OS on the restore machine is different anyway. CRaC therefore does not silently snapshot everything: it demands that open resources be *closed before* the checkpoint and *reopened after* restore. If open file descriptors remain that nobody registered, CRaC raises a `CheckpointException`. This is where the word *Coordinated* comes from — the runtime coordinates with the application so state is released and reacquired around the snapshot. **How Spring plugs in.** Spring Framework 6.1 (Spring Boot 3.2) added first-class CRaC support. Spring depends on the small `org.crac:crac` facade library, which delegates to the JDK's CRaC API when present and is a no-op otherwise. Spring's `DefaultLifecycleProcessor` registers the application context as an `org.crac.Resource` on the global CRaC context. The `org.crac.Resource` interface has two callbacks: `beforeCheckpoint(Context)` and `afterRestore(Context)`. - On **`beforeCheckpoint`**, Spring stops the context's lifecycle: it invokes `stop()` on all running `Lifecycle`/`SmartLifecycle` beans, in **descending phase order** (the reverse of startup). Well-behaved beans use `stop()` to close connection pools, shut network listeners, and flush buffers so no live OS resources remain. - On **`afterRestore`**, Spring calls `start()` on those beans, in **ascending phase order**, so pools reopen and listeners rebind — now against whatever infrastructure the restored instance sees. **Two ways to trigger a checkpoint.** (1) *On demand* while the app runs: `jcmd <pid> JDK.checkpoint`, with the JVM started using `-XX:CRaCCheckpointTo=<dir>`. (2) *Automatically at startup*: set the Spring property `spring.context.checkpoint=onRefresh`, which makes Spring take a checkpoint at the end of context refresh. Restore in both cases with `java -XX:CRaCRestoreFrom=<dir>`. **When to use it.** CRaC is an alternative to GraalVM native image for fast startup and fast scale-to-zero / serverless. Unlike native image it keeps the full JVM (dynamic proxies, reflection, JIT peak performance), but it needs a special JDK and careful handling of external state. **Key terms.** *Lifecycle* — a Spring interface with `start()`/`stop()`/`isRunning()`. *SmartLifecycle* — extends it with `getPhase()` and auto-start. *Checkpoint* — the snapshot. *Restore* — booting a process from it.

  • Can you take a CRaC checkpoint on a regular OpenJDK build?
    No. CRaC requires a CRaC-enabled JDK (for example Azul Zulu with CRaC). The `org.crac` facade compiles everywhere but only performs a real checkpoint on a CRaC runtime; otherwise it's a no-op.
  • Why doesn't Spring just let CRaC snapshot the open connections as-is?
    A memory snapshot can't preserve live OS handles — sockets/file descriptors would be stale on restore and would point at infrastructure that may no longer exist. CRaC also fails the checkpoint if unmanaged FDs are open, so Spring closes them via stop() and reopens via start().

saying these in an interview costs you the question

  • Thinking CRaC works on any JDK without a special build
  • Believing open DB connections are snapshotted and 'just work' after restore
  • Confusing CRaC (full JVM snapshot) with GraalVM native image (ahead-of-time compiled binary)

context

open as a page

What are the ways to trigger a CRaC checkpoint with Spring, and how does spring.context.checkpoint=onRefresh differ from an on-demand checkpoint?

level: middleimportance: should knowfreq 22%

basics

~10 s

Two ways: set spring.context.checkpoint=onRefresh to auto-checkpoint during startup (context refreshed but lifecycle beans not yet started), or run jcmd <pid> JDK.checkpoint on a fully running app. Restore both with java -XX:CRaCRestoreFrom=<dir>.

open as a page

Why must resources like connection pools be released before a CRaC checkpoint, and how does Spring coordinate that through the Lifecycle contract?

level: seniorimportance: should knowfreq 18%

basics

~20 s

A memory snapshot can't hold live OS handles; CRaC even fails the checkpoint if unmanaged file descriptors are open. Spring registers the context as a CRaC resource and, in beforeCheckpoint, calls stop() on Lifecycle beans (descending phase) to close pools/sockets, then start() on restore.

open as a page

How do you make a custom resource participate in Spring's CRaC checkpoint/restore, and when would you use org.crac.Resource directly instead of SmartLifecycle?

level: seniorimportance: nice to knowfreq 12%

basics

~20 s

Usually implement SmartLifecycle: close in stop(), reopen in start(), and Spring handles the CRaC callbacks. Use org.crac.Resource directly (register on Core.getGlobalContext()) for non-Spring components or when you need CRaC hooks decoupled from Spring's lifecycle phases.

open as a page

As a principal engineer, what operational and security gotchas would you weigh before adopting Spring CRaC, and how does it compare to GraalVM native image?

level: principalimportance: nice to knowfreq 14%

basics

~20 s

CRaC needs a special JDK and a snapshot that may embed secrets and stale time/RNG/DNS state; every restored instance shares that memory, so reseed randomness and refresh time-sensitive state after restore. Versus native image: CRaC keeps the full JVM and JIT but is less portable and heavier to operate.

open as a page