Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Analyzing BootstrapContext and Its Default Implementation in Spring Boot

Tech 1

The BootstrapContext interface provides lazy access to shared or expensive singleton objects during startup, before the ApplicationContext becomes ready. It remains available throughout environment post-processing.

public interface BootstrapContext {
    <T> T get(Class<T> requiredType) throws IllegalStateException;
    <T> T getOrElse(Class<T> requiredType, T fallback);
    <T> T getOrElseSupply(Class<T> requiredType, Supplier<T> fallbackSupplier);
    <T, X extends Throwable> T getOrElseThrow(Class<T> requiredType, Supplier<? extends X> exSupplier) throws X;
    <T> boolean isRegistered(Class<T> requiredType);
}
  • get: Retrieves an instance of the specified type if it has been registered; otherwise creates it. Throws if unavailable.
  • getOrElse: Returns the registered instance or the supplied fallback value if unregistered.
  • getOrElseSupply: Returns the registered instance or obtains one from the given supplier when missing.
  • getOrElseThrow: Returns the registered instance or throws the exception produced by the given supplier.
  • isRegistered: Checks whether a particular type has been registered.

ConfigurableBootstrapContext

public interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext { }

This composite interface combines registration and retrieval capabilities, enabling full control over bootstrap configuration. Implementations can manage both instance suppliers and direct instance storage.

DefaultBootstrapContext Implementation

DefaultBootstrapContext is the out-of-the-box implementation used by Spring Boot.

public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
    private final Map<Class<?>, InstanceSupplier<?>> supplierMap = new HashMap<>();
    private final Map<Class<?>, Object> instanceCache = new HashMap<>();
    private final ApplicationEventMulticaster eventBroadcaster = new SimpleApplicationEventMulticaster();

    public void close(ConfigurableApplicationContext appCtx) {
        this.eventBroadcaster.multicastEvent(new BootstrapContextClosedEvent(this, appCtx));
    }
}
  • supplierMap: Associates a type with its InstanceSupplier, responsible for producing the instance.
  • instanceCache: Holds already-created singleton instances keyed by type.
  • eventBroadcaster: Dispatches bootstrap lifecycle events to listeners.

Registration Methods

public <T> void register(Class<T> type, InstanceSupplier<T> supplier) {
    register(type, supplier, true);
}

public <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> supplier) {
    register(type, supplier, false);
}

private <T> void register(Class<T> type, InstanceSupplier<T> supplier, boolean allowReplace) {
    Assert.notNull(type, "Type must not be null");
    Assert.notNull(supplier, "Supplier must not be null");
    synchronized (this.supplierMap) {
        boolean present = this.supplierMap.containsKey(type);
        if (allowReplace || !present) {
            Assert.state(!this.instanceCache.containsKey(type),
                () -> type.getName() + " instance already created");
            this.supplierMap.put(type, supplier);
        }
    }
}
  • register always overwrites an existing entry; registerIfAbsent only registers when absent.
  • Thread safety is ensured via synchronization on supplierMap.
public <T> boolean isRegistered(Class<T> type) {
    synchronized (this.supplierMap) {
        return this.supplierMap.containsKey(type);
    }
}

@SuppressWarnings("unchecked")
public <T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type) {
    synchronized (this.supplierMap) {
        return (InstanceSupplier<T>) this.supplierMap.get(type);
    }
}

public void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> lst) {
    this.eventBroadcaster.addApplicationListener(lst);
}

Retrieval Methods

public <T> T get(Class<T> type) throws IllegalStateException {
    return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " not registered"));
}

public <T> T getOrElse(Class<T> type, T alt) {
    return getOrElseSupply(type, () -> alt);
}

public <T> T getOrElseSupply(Class<T> type, Supplier<T> altSupplier) {
    synchronized (this.supplierMap) {
        InstanceSupplier<?> supplier = this.supplierMap.get(type);
        return supplier != null ? getInstance(type, supplier) : altSupplier.get();
    }
}

public <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exSupplier) throws X {
    synchronized (this.supplierMap) {
        InstanceSupplier<?> supplier = this.supplierMap.get(type);
        if (supplier == null) throw exSupplier.get();
        return getInstance(type, supplier);
    }
}

Both getOrElseSupply and getOrElseThrow delegate instance creation to getInstance when a supplier exists.

@SuppressWarnings("unchecked")
private <T> T getInstance(Class<T> type, InstanceSupplier<?> supplier) {
    T obj = (T) this.instanceCache.get(type);
    if (obj == null) {
        obj = (T) supplier.get(this);
        if (supplier.getScope() == Scope.SINGLETON) {
            this.instanceCache.put(type, obj);
        }
    }
    return obj;
}
  • First checks instanceCache; if missing, invokes the supplier.
  • Caches the result for singleton-scoped suppliers.

Lifecycle Close Method

When bootstrapping ends and the application context is prepared, close broadcasts BootstrapContextClosedEvent to all listeners added via addCloseListener. This allows cleanup or finalization tied to bootstrap completion.

Tags: Spring Boot

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.