Spring Boot Starter architecture

This page provides a technical overview of the Atoti What-If Spring Boot Starter architecture for developers who need to understand how auto-configuration works.

Module structure

The starter is split into three modules:

Module Artifact ID Description
Library atoti-what-if-lib Core business logic, interfaces, and implementations
Configuration atoti-what-if-config Auto-configuration classes and property bindings
Starter atoti-what-if-spring-boot-starter Dependency aggregator that pulls in lib and config

The starter module contains no code. It serves as a single dependency that transitively includes the library and configuration modules.

Auto-configuration classes

Each auto-configuration class is responsible for a specific functional area:

Class Beans Created Condition
WhatIfCoreConfig DatabaseSimulationEngine, IUniqueIdGenerator Always active
WhatIfPersistenceConfig SessionFactory, ISimulationPersistenceManager IWhatIfPersistenceProperties bean present
WhatIfSecurityConfig IDatabaseSimulationsSecurityManager Based on security.type property
WhatIfWorkflowConfig IDatabaseSimulationsWorkflow Always active
WhatIfRestConfig DatabaseSimulationsRestService, exception handler Always active
WhatIfDistributionConfig RestDistributedDatabaseService, address/auth suppliers distribution.enabled: true

Bean creation order

Beans are created in dependency order:

┌─────────────────────────┐
│  IWhatIfPersistence     │ (provided by application)
│      Properties         │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐     ┌─────────────────────────┐
│   SessionFactory        │     │  DatabaseSimulation     │
│   (Persistence)         │     │      Engine             │
└───────────┬─────────────┘     └───────────┬─────────────┘
            │                               │
            ▼                               │
┌─────────────────────────┐                 │
│  ISimulationPersistence │                 │
│      Manager            │                 │
└───────────┬─────────────┘                 │
            │                               │
            ▼                               │
┌─────────────────────────┐                 │
│  IDatabaseSimulations   │                 │
│   SecurityManager       │                 │
└───────────┬─────────────┘                 │
            │                               │
            ▼                               ▼
┌─────────────────────────────────────────────┐
│         IDatabaseSimulationsWorkflow        │
└───────────────────┬─────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────┐
│        DatabaseSimulationsRestService       │
└─────────────────────────────────────────────┘

The SessionFactory bean (named whatIfSessionFactory) can be overridden independently of ISimulationPersistenceManager. It includes destroyMethod = "close" to ensure proper resource cleanup on application shutdown.

Conditional annotations

The auto-configuration uses Spring Boot conditional annotations:

@ConditionalOnMissingBean

All beans use @ConditionalOnMissingBean, allowing application-defined beans to take precedence:

@Bean
@ConditionalOnMissingBean
public IUniqueIdGenerator idGenerator() {
    return new IncrementalUniqueIdGenerator();
}

@ConditionalOnProperty

Property-based conditions control feature activation:

@ConditionalOnProperty(
    prefix = "atoti.what-if",
    name = "distribution.enabled",
    havingValue = "true")
public class WhatIfDistributionConfig { ... }

@ConditionalOnWhatIfEnabled

A custom conditional annotation that gates all What-If beans on the atoti.what-if.enable property. It combines two condition classes for different Spring lifecycle phases:

  • ConfigurationEnabledWhatIf — evaluates during PARSE_CONFIGURATION phase (applies to @Configuration classes)
  • BeanEnabledWhatIf — evaluates during REGISTER_BEAN phase (applies to @Bean methods)
@ConditionalOnWhatIfEnabled
@Configuration
public class WhatIfCoreConfig {
    // Beans here are only registered when atoti.what-if.enable is true (default)
}

Setting atoti.what-if.enable: false disables all auto-configuration classes annotated with @ConditionalOnWhatIfEnabled.

@ConditionalOnWhatIfDistributionEnabled

A custom conditional annotation that gates Atoti What-If distribution beans on the atoti.what-if.distribution.enabled property. Like @ConditionalOnWhatIfEnabled, it combines two condition classes for different Spring lifecycle phases:

  • ConfigurationEnabledWhatIfDistribution — evaluates during PARSE_CONFIGURATION phase (applies to @Configuration classes)
  • BeanEnabledWhatIfDistribution — evaluates during REGISTER_BEAN phase (applies to @Bean methods)

Unlike @ConditionalOnWhatIfEnabled, this annotation does not default to enabled. When the property is absent, distribution beans are not registered.

The annotation is typically used alongside @ConditionalOnWhatIfEnabled on WhatIfDistributionConfig:

@ConditionalOnWhatIfEnabled
@ConditionalOnWhatIfDistributionEnabled
@Configuration
public class WhatIfDistributionConfig {
    // Beans here require both atoti.what-if.enable (default: true)
    // AND atoti.what-if.distribution.enabled=true
}

Setting atoti.what-if.distribution.enabled: true activates distribution features. Defaults to false.

Property binding

Properties are bound using @ConfigurationProperties:

@ConfigurationProperties(prefix = "atoti.what-if")
public class WhatIfProperties {
    private final boolean enable;
    private final Security security;
    private final Distribution distribution;
    // ...
}

Nested records provide type-safe configuration:

public record Security(SecurityType type, boolean useBranchPermissions) {
    public Security(
            @DefaultValue("SPRING") SecurityType type,
            @DefaultValue("true") boolean useBranchPermissions) {
        this.type = type;
        this.useBranchPermissions = useBranchPermissions;
    }
}

Extension points

Overriding beans

Define a bean of the same type to override auto-configuration:

@Bean
public IUniqueIdGenerator customIdGenerator() {
    return new MyIdGenerator();  // Takes precedence
}

See How to customize auto-configured beans for detailed examples.

Required application beans

The starter requires these beans from your application:

Bean Purpose
IDatabaseService Provided by Atoti Server for datastore operations
IWhatIfPersistenceProperties Provides Hibernate configuration for persistence

Without these beans, the corresponding auto-configuration is skipped or fails.