# DDDBootstrap Initialization Sequence: When `RegistryFactory.register()` is Invoked in cp-ddd-framework

> Discover the DDDBootstrap initialization sequence and learn exactly when RegistryFactory register is invoked within cp-ddd-framework after Spring dependency injection and before ContextRefreshedEvent.

- Repository: [Funky Gao/cp-ddd-framework](https://github.com/funkygao/cp-ddd-framework)
- Tags: internals
- Published: 2026-03-02

---

**`RegistryFactory.register()` is invoked exactly once during `DDDBootstrap#setApplicationContext`, which occurs after Spring injects dependencies but before the `ContextRefreshedEvent` fires.**

The **DDDBootstrap** class serves as the internal Spring bootstrapper for the funkygao/cp-ddd-framework, orchestrating the registration of all DDD-plus annotated components into the runtime registry. Understanding its initialization sequence is essential for debugging startup issues or extending the framework with custom registry entries.

## Overview of the Bootstrap Architecture

`DDDBootstrap` implements two critical Spring interfaces: `ApplicationContextAware` and `ApplicationListener<ContextRefreshedEvent>`. This dual implementation allows it to hook into the Spring lifecycle at two distinct phases: pre-refresh configuration and post-refresh completion.

The companion class **`RegistryFactory`** (also a Spring `@Component`) performs the actual bean registration logic. It maintains two internal collections populated during its own initialization phase:

- **`validRegistryEntries`** – Ordered list of handlers for core DDD annotations (Domain, Interceptor, etc.)
- **`validPrepareEntries`** – Map for plugin-type annotations (Partner, Extension)

## Step-by-Step Initialization Sequence

The framework follows a strict seven-phase initialization process:

### 1. Component Scanning and Bean Creation

Spring scans the classpath and instantiates singleton beans for both `DDDBootstrap` and `RegistryFactory`. Both classes carry the `@Component` annotation, making them candidates for classpath scanning.

```java
// DDDBootstrap.java, lines 24-27
@Component
public class DDDBootstrap implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
    // ...
}

```

### 2. RegistryFactory Preparation

Because `RegistryFactory` implements `InitializingBean`, Spring invokes `afterPropertiesSet()` immediately after dependency injection. This method populates the registry metadata that will be used later.

In [`RegistryFactory.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/RegistryFactory.java) (lines 55-71), the method initializes `validRegistryEntries` with ordered `IRegistryAware` implementations and prepares `validPrepareEntries` for plugin annotations.

### 3. Dependency Injection

Spring injects the `RegistryFactory` instance into `DDDBootstrap` via the `@Resource` annotation:

```java
// DDDBootstrap.java, lines 29-31
@Resource
private RegistryFactory registryFactory;

```

### 4. ApplicationContext Callback (The Registration Trigger)

When the Spring container is ready, it calls `DDDBootstrap#setApplicationContext(ApplicationContext)`. This method uses an `AtomicBoolean` to guarantee **once-only execution**, then immediately delegates to the registry factory:

```java
// DDDBootstrap.java, lines 37-50
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
    if (!initialized.compareAndSet(false, true)) {
        return; // Ensure single execution
    }
    // ...
    registryFactory.register(applicationContext);  // Critical registration point
    DDDBootstrap.applicationContext = applicationContext;
}

```

**This is the exact moment `RegistryFactory.register()` is invoked**—after bean creation and injection, but before the context refresh completes.

### 5. RegistryFactory.register() Execution

The `register()` method (lines 30-40 in [`RegistryFactory.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/RegistryFactory.java)) iterates over `validRegistryEntries`. For each entry, it:

1. Retrieves all Spring beans annotated with the specific DDD annotation via `applicationContext.getBeansWithAnnotation()`
2. Invokes the corresponding `IRegistryAware` implementation (e.g., `DomainDef`, `StepDef`, `RouterDef`) to register each bean
3. Triggers `InternalIndexer.postIndexing()` to finalize internal indexes after all beans are processed

### 6. Post-Indexing Finalization

After `register()` completes, `InternalIndexer.postIndexing()` builds runtime indexes required for pattern matching and router resolution. This must happen while the context is still initializing to ensure all infrastructure is ready before user code executes.

### 7. ContextRefreshedEvent Completion

Once Spring finishes refreshing the `ApplicationContext`, it fires a `ContextRefreshedEvent`. `DDDBootstrap` receives this event and:

- Logs startup completion
- Optionally invokes `IStartupListener#onStartComplete()` if a user-provided listener bean exists

This occurs in [`DDDBootstrap.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/DDDBootstrap.java) (lines 52-63), marking the end of the bootstrap sequence.

## Critical Timing: When is RegistryFactory.register() Called?

`RegistryFactory.register()` executes **exactly once** during the `setApplicationContext` callback. This timing is deliberate and provides specific guarantees:

- **Before bean usage**: Registration completes before any user code can access DDD components via `ApplicationContext.getBean()`
- **After dependency resolution**: All `@Autowired` dependencies within registry entries are satisfied before registration occurs
- **Thread-safe**: The `AtomicBoolean` check prevents double execution in complex refresh scenarios

The call chain follows this strict order:

```

DDDBootstrap#setApplicationContext 
    → RegistryFactory.register(applicationContext) 
    → InternalIndexer.postIndexing()

```

## Accessing DDD Beans After Bootstrapping

Once the sequence completes, you can safely retrieve DDD components through the static context reference maintained by `DDDBootstrap`:

```java
// Obtain the Spring ApplicationContext stored during bootstrap
ApplicationContext ctx = DDDBootstrap.applicationContext();

// Retrieve a registered DDD+ bean by type
MyDomainService service = ctx.getBean(MyDomainService.class);

// Execute domain logic
service.doSomething();

```

This approach works because `DDDBootstrap.applicationContext()` returns the same context instance passed to `RegistryFactory.register()`, ensuring all annotated beans have been processed and indexed.

## Summary

- **DDDBootstrap** coordinates the startup sequence using Spring's `ApplicationContextAware` and `ApplicationListener` interfaces.
- **`RegistryFactory.register()`** is invoked exactly once inside `DDDBootstrap#setApplicationContext`, guarded by an `AtomicBoolean`.
- The registration process scans for DDD annotations (Domain, Step, Router, etc.) and delegates to specific `IRegistryAware` handlers.
- **`InternalIndexer.postIndexing()`** finalizes the registry immediately after bean registration completes.
- The entire sequence finishes before the `ContextRefreshedEvent` fires, ensuring runtime readiness when user code begins execution.

## Frequently Asked Questions

### What prevents RegistryFactory.register() from being called multiple times?

An `AtomicBoolean` named `initialized` inside `DDDBootstrap` ensures the registration logic executes only once. When `setApplicationContext` is invoked, it attempts a `compareAndSet(false, true)` operation. If the bootstrapper has already run, the method returns immediately without re-invoking `registryFactory.register()`.

### How does the framework handle different types of DDD annotations during registration?

`RegistryFactory` maintains two distinct collections initialized in `afterPropertiesSet()`. The `validRegistryEntries` list handles core framework annotations like Domain and Interceptor, while `validPrepareEntries` manages plugin-oriented annotations such as Partner and Extension. Each entry maps to a specific `IRegistryAware` implementation that understands how to process its annotation type.

### Can I access DDD beans before the ContextRefreshedEvent completes?

Yes. Beans registered during the `RegistryFactory.register()` phase are available immediately after that method returns, which occurs before `ContextRefreshedEvent` fires. However, you should rely on the standard `DDDBootstrap.applicationContext()` accessor to ensure you access the context after the static reference has been set in `setApplicationContext()`.

### What happens if a bean fails to register during the bootstrap sequence?

If an `IRegistryAware` implementation throws an exception during registration in `RegistryFactory.register()`, the exception propagates up through `setApplicationContext`, causing the Spring context initialization to fail fast. This prevents the application from starting in a partially configured state where some DDD components might be missing from the internal indexes.