Analysis and Solutions for Spring Bean Creation Exception: Singleton Bean Creation Not Allowed

Dec 06, 2025 · Programming · 15 views · 7.8

Keywords: Spring Framework | Bean Creation Exception | JUnit Testing

Abstract: This paper provides an in-depth exploration of the common BeanCreationNotAllowedException in the Spring framework, particularly the "Singleton bean creation not allowed while the singletons of this factory are in destruction" error. By analyzing typical scenarios in JUnit testing environments and integrating best practice solutions, it systematically examines the root causes, triggering mechanisms, and multiple resolution strategies. The article not only explains core concepts such as Java environment configuration, multi-threading timing, and BeanFactory lifecycle in detail but also offers code examples and debugging recommendations to help developers prevent and resolve such issues fundamentally.

Exception Phenomenon and Background

During JUnit test execution in Spring applications, developers often encounter the org.springframework.beans.factory.BeanCreationNotAllowedException exception, with typical error messages like: Error creating bean with name 'somarFactory': Singleton bean creation not allowed while the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!). This indicates an attempt to create a new singleton bean during the BeanFactory's destruction phase, violating Spring container lifecycle management rules.

Core Cause Analysis

The fundamental cause of this exception lies in BeanFactory state management conflicts. During the destruction phase, the Spring container closes all singleton beans, placing it in a "destruction in progress" state where creating new singleton beans is prohibited. This typically occurs in scenarios such as:

Primary Solutions

Based on best practices and community experience, resolving this issue requires a multi-dimensional approach:

1. Environment Configuration Check
Ensure the JAVA_HOME environment variable correctly points to a valid JDK installation path. For example, in Unix/Linux systems:

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

Simultaneously verify JDK version compatibility, recommending Spring-officially supported versions (e.g., JDK 8 or 11). This can be checked with:

System.out.println("Java version: " + System.getProperty("java.version"));
System.out.println("Java home: " + System.getProperty("java.home"));

2. Container Instance Management
In testing environments, ensure only one Spring container instance is running. Avoid multiple BeanFactory coexistence due to repeated Tomcat or other server startups. For example, correctly using the @SpringBootTest annotation in JUnit tests:

@SpringBootTest
@RunWith(SpringRunner.class)
public class SomarFactoryTest {
    @Autowired
    private ApplicationContext context;
    
    @Test
    public void testBeanCreation() {
        // Test logic
    }
}

3. Lifecycle Control
In multi-threaded scenarios, ensure all bean invocations complete before closing the container. Avoid calling context.close() in unfinished threads. Example:

ExecutorService executor = Executors.newFixedThreadPool(5);
List<Future> futures = new ArrayList<>();

for (int i = 0; i < 10; i++) {
    futures.add(executor.submit(() -> {
        // Invoke bean method
        somarFactory.doSomething();
    }));
}

// Wait for all tasks to complete
for (Future future : futures) {
    future.get();
}

executor.shutdown();
// Now safe to close container
// context.close();  // Determine based on actual situation

In-Depth Technical Details

During the destruction phase, Spring's BeanFactory iterates through all singleton beans, invoking their destruction methods. This process is unidirectional and irreversible; once in destruction state, any request to create new singletons triggers an exception. The internal mechanism can be understood through this pseudo-code:

public class DefaultSingletonBeanRegistry {
    private boolean singletonsCurrentlyInDestruction = false;
    
    protected void beforeSingletonCreation(String beanName) {
        if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                "Singleton bean creation not allowed while singletons are in destruction");
        }
        // ... Other check logic
    }
    
    public void destroySingletons() {
        this.singletonsCurrentlyInDestruction = true;
        try {
            // Destroy all singleton beans
            for (String beanName : this.singletonNames) {
                destroySingleton(beanName);
            }
        } finally {
            this.singletonsCurrentlyInDestruction = false;
        }
    }
}

This design ensures container state consistency, preventing unpredictable bean dependency relationships during destruction.

Prevention and Best Practices

To avoid such exceptions, follow these development guidelines:

By systematically understanding Spring container lifecycle management and state transition mechanisms, developers can more effectively diagnose and resolve BeanCreationNotAllowedException exceptions, enhancing application stability and maintainability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.