Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring bean scopes: singleton identity is not thread safety

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A bean scope determines the ownership and reuse of instances created from a bean definition.

Download Spring source kit

This lesson uses the downloadable source kit: Java 21, Spring Boot 4.0.8 and its managed Spring Framework 7 dependencies. The version is pinned for repeatable builds.

Count instances at the ownership boundary

The report is a singleton in its context. ImportBuffer is prototype-scoped, and two provider resolutions return different instances. The test checks identity rather than comparing equal capacity values; equal values do not establish shared ownership.

A prototype injected once into a singleton remains that one injected reference. It does not turn into a new buffer on every method call. Use an explicit provider when a service genuinely requires a new instance per operation.

Shared mutable state needs its own rule

ReceiptStore is a singleton service. Its synchronized methods protect the map and identifier increment together, and page() returns an immutable snapshot. Removing the lock because Spring owns the service would create races in ordinary Java state.

Request and session scopes require a web-aware owner. Prototype objects with expensive resources need client cleanup; they do not inherit singleton destruction semantics. Before selecting a scope, decide who owns the resource and who can prove that ownership ended.

Checked source

Java
context.registerBean(ImportBuffer.class, ImportBuffer::new,
    definition -> definition.setScope(BeanDefinition.SCOPE_PROTOTYPE));
ObjectProvider<ImportBuffer> buffers = context.getBeanProvider(ImportBuffer.class);
boolean different = buffers.getObject() != buffers.getObject();

Test the boundary

Run mvn test in the source-kit directory. CoreBoundaryTest checks the behavior described here. Java excerpts belong to the named source-kit classes; they are not independent source files unless the complete class is shown.

Costs and boundaries

Singleton reuse can reduce allocations while increasing contention on shared state. Prototype allocation grows with resolutions and may retain external resources until the caller releases them. The kit’s buffer contains no native resource.

Common Mistakes

  • A singleton is not an automatic concurrency guarantee.
  • Prototype injection into a singleton occurs at injection time.
  • Do not assume prototype destruction is managed like singleton destruction.

Read next

Object provider, Lifecycle cleanup, Java threads: visibility, atomicity, and shared counters.

Next boundary checks

Continue with Spring request scope proxy: resolve state for the current HTTP request.

Continue with the new boundary checks

Continue with Spring session scope: one target across requests, separate targets across sessions.

spring
spring-boot
bean-scopes
Storage details