# How InternalIndexer Organizes and Post-Indexes Registered Domain Artifacts in DDDplus

> Discover how DDDplus's InternalIndexer organizes and post-indexes registered domain artifacts. This in-memory registry collects, categorizes, and exports domain artifacts for deterministic runtime resolution.

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

---

**The InternalIndexer serves as DDDplus's central in-memory registry that automatically collects, categorizes, and exports all domain artifacts during Spring bean initialization, enabling deterministic resolution of extensions, steps, and policies at runtime.**

The InternalIndexer is the backbone of artifact management in the DDDplus framework (funkygao/cp-ddd-framework), responsible for organizing registered domain artifacts into a queryable structure. This component operates during the bootstrap phase to index domains, steps, routers, extensions, patterns, partners, and policies, creating a lightweight, immutable snapshot of the domain model for downstream consumption.

## How InternalIndexer Collects Domain Artifacts During Registration

During Spring context initialization, each domain artifact implements `IRegistryAware` and registers itself with the `InternalIndexer` through overloaded `index()` methods. This process populates distinct concurrent hash maps that isolate artifacts by type for thread-safe access.

### Indexing Domain Definitions

When the Spring container instantiates a class annotated with `@Domain`, the `DomainDef` object invokes `InternalIndexer.index(DomainDef)` in [`dddplus-runtime/src/main/java/io/github/dddplus/runtime/registry/InternalIndexer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-runtime/src/main/java/io/github/dddplus/runtime/registry/InternalIndexer.java). This stores the domain metadata in `domainDefMap`, mapping the domain code to its definition object.

### Registering Steps and Routers

Domain steps follow a similar pattern. When a class implementing `IDomainStep` is annotated with `@Step`, the `StepDef` captures the activity code, step code, name, and tags before calling `InternalIndexer.index(this)`. This populates `domainStepDefMap`, enabling later retrieval of steps by activity code.

Routers extending `BaseRouter` are indexed via `InternalIndexer.index(RouterDef)`, which stores definitions in `routerDefMap` for runtime routing decisions.

### Handling Extensions, Policies, and Patterns

Extensions represent the most complex indexing logic. When `ExtensionDef` registers itself, the indexer determines whether it belongs to a **Policy**, **Pattern**, or **Partner** route:

- **Policies** are stored in `policyDefMap` and `policyClazzMap`, linking policy classes to their extension interfaces.
- **Patterns** are accumulated in `patternDefMap` before being sorted by priority in the post-indexing phase.
- **Partners** are maintained in the concurrent `partnerDefMap`, keyed by partner code.

Interceptors implementing `IExtensionInterceptor` can be registered once via `index(InterceptorDef)`.

## The Post-Indexing Phase: Sorting and Exporting Artifacts

After all Spring beans initialize, `DDDBootstrap` triggers `InternalIndexer.postIndexing()`. This method transitions the system from registration mode to runtime mode through two critical operations.

### Pattern Prioritization and Cleanup

First, the indexer transfers all `PatternDef` objects from `patternDefMap` to `sortedPatternMap`, sorting them by their `priority` value. This ensures deterministic resolution where higher-priority patterns match before lower-priority ones during extension routing.

Immediately after sorting, `patternDefMap` is cleared to free memory, as the unsorted temporary storage is no longer needed at runtime.

### Exporting to DomainArtifacts

The final post-indexing action calls `DomainArtifacts.getInstance().export()`. This utility reads the internal maps of `InternalIndexer` and constructs three immutable collections:

- **Domains**: A list of `Domain` objects containing codes and names.
- **Steps**: A map of `activityCode → List<Step>` with step codes, names, and tags.
- **Extensions**: For each extension interface, a record of applicable patterns and partner implementations.

The resulting `DomainArtifacts` object provides a lightweight, read-only snapshot that external configuration centers and visualization dashboards can consume without accessing the mutable internal registries.

## Runtime Lookup Helpers in InternalIndexer

Beyond registration and export, `InternalIndexer` provides static utility methods used by the DDDplus runtime to resolve artifacts dynamically:

- `findRouter(Class<? extends BaseRouter>)` – Retrieves a router instance from `routerDefMap` for request routing.
- `extClazzOfPolicy(Class<? extends IPolicy>)` – Resolves the extension interface associated with a given policy class using `policyClazzMap`.
- `findEffectiveExtensions(Class<? extends IDomainExtension>, IIdentity, boolean)` – Returns concrete extension implementations applicable to a business identity, respecting the priority order: **Policy → Pattern → Partner**.
- `findDomainSteps(String activityCode, List<String> stepCodeList)` – Retrieves step definitions belonging to a specific domain activity from `domainStepDefMap`.

These helpers enable the framework to maintain a **deterministic, hierarchical, and extensible** architecture while keeping the internal registry encapsulated.

## Practical Code Examples

The following examples demonstrate how domain artifacts register themselves and how applications interact with the indexer at runtime.

```java
// Domain definition registration
@Domain(code = "WMS", name = "Warehouse Management")
public class WmsDomain {}

// Step registration with activity and step codes
@Step(name = "创建出库单", tags = {"create", "outbound"})
public class CreateOutboundStep implements IDomainStep {
    @Override 
    public String activityCode() { return "OUTBOUND"; }
    
    @Override 
    public String stepCode() { return "CREATE"; }
}

// Router registration
@Router
public class OutboundRouter extends BaseRouter {}

// Extension and Policy registration
@Policy(name = "OutboundPolicy")
public class OutboundPolicy implements IPolicy<OutboundExt, Identity> {}

@Extension
public class OutboundExtImpl implements OutboundExt {
    // Implementation details
}

// Pattern registration with priority
@Pattern(code = "VIP", priority = 1)
public class VipPattern implements IExtensionPattern {}

// Partner registration
@Partner(code = "KA")
public class KaPartner implements IPartner {}

// Runtime lookup examples
BaseRouter router = InternalIndexer.findRouter(OutboundRouter.class);

List<ExtensionDef> extensions = InternalIndexer.findEffectiveExtensions(
    OutboundExt.class, 
    new Identity("customerId", "VIP"), 
    false
);

List<StepDef> steps = InternalIndexer.findDomainSteps(
    "OUTBOUND", 
    Arrays.asList("CREATE")
);

```

When the Spring context initializes, `DDDBootstrap` automatically triggers the registration process. Each annotated class invokes `InternalIndexer.index()` to store its metadata, followed by `postIndexing()` to sort patterns and export the final `DomainArtifacts` snapshot.

## Summary

- **InternalIndexer** acts as the central registry in `dddplus-runtime`, collecting all domain artifacts during Spring bean initialization through type-specific `index()` methods.
- Artifacts are stored in isolated concurrent maps (`domainDefMap`, `domainStepDefMap`, `routerDefMap`, `patternDefMap`, `partnerDefMap`, `policyDefMap`) to ensure thread-safe registration.
- The **post-indexing phase** sorts `PatternDef` objects by priority into `sortedPatternMap`, clears temporary storage, and exports an immutable `DomainArtifacts` snapshot for external tools.
- Runtime lookup helpers like `findEffectiveExtensions()` and `findDomainSteps()` enable deterministic resolution of extensions and steps based on business identity and activity codes.

## Frequently Asked Questions

### How does InternalIndexer handle concurrent registration during Spring initialization?

`InternalIndexer` uses concurrent hash maps (`ConcurrentHashMap`) for all artifact storage, including `domainDefMap`, `partnerDefMap`, and `routerDefMap`. Since Spring's bean initialization is single-threaded by default, the concurrent structures primarily provide safety guarantees during runtime lookups rather than concurrent registration. Each artifact type implements `IRegistryAware` and synchronously invokes its respective `index()` method before the container finishes initialization.

### What determines the priority order when multiple patterns match an extension request?

During `postIndexing()`, `InternalIndexer` transfers all `PatternDef` objects from `patternDefMap` to `sortedPatternMap`, sorting them by the `priority` field in descending order. When `findEffectiveExtensions()` resolves an extension for a business identity, it evaluates patterns in this sorted order. Higher priority values are checked first, ensuring deterministic resolution where the most specific pattern matches before more general ones. After sorting, the temporary `patternDefMap` is cleared to reduce memory footprint.

### How can external systems access the indexed domain metadata without directly querying InternalIndexer?

External tools should consume the `DomainArtifacts` object exported during `postIndexing()`. When `InternalIndexer.postIndexing()` executes, it triggers `DomainArtifacts.getInstance().export()`, which reads the internal maps and constructs three immutable collections: domains (codes and names), steps (grouped by activity code), and extensions (with their applicable patterns and partners). This snapshot provides a lightweight, read-only view suitable for configuration centers, visualization dashboards, and documentation generators without exposing the mutable internal registries.

### What is the difference between Policy, Pattern, and Partner routes in extension indexing?

`InternalIndexer` categorizes extensions into three hierarchical resolution strategies during registration. **Policies** (stored in `policyDefMap`) link a policy class directly to an extension interface, enabling rule-based selection. **Patterns** (stored temporarily in `patternDefMap` then sorted into `sortedPatternMap`) match extensions based on business identity attributes with priority-based ordering. **Partners** (stored in `partnerDefMap`) provide specific implementations for particular business partners or customers. At runtime, `findEffectiveExtensions()` resolves these in order: Policy first, then Pattern, then Partner, ensuring the most specific applicable implementation is returned.