Java
javaTutorial
Customize the bean name generator in Spring Boot tests to resolve naming conflicts
Customize the bean name generator in Spring Boot tests to resolve naming conflicts

This article explores how to solve `BeanDefinitionOverrideException` by customizing the Bean name generator when introducing multiple components with the same name but different packages in Spring Boot integration tests. By defining a `@Configuration` configuration class inside the test class, and combining `@ComponentScan` to specify `FullyQualifiedAnnotationBeanNameGenerator` and `basePackageClasses`, you can effectively create an isolated and conflict-free Bean context for the test environment, ensuring the stability and accuracy of the test.
Bean name conflict problem in Spring Boot testing
When using Spring Boot for integration testing, we usually use the @SpringBootTest annotation to load the application context. However, when tests need to be run against a subset of the application (specified through the classes attribute), and these subsets contain multiple components with the same class name in different packages, you may encounter a BeanDefinitionOverrideException exception.
For example, consider the following scenario, com.bar.ConflictName and com.foo.ConflictName are components with the same name under two different packages:
// com/bar/ConflictName.kt package com.bar import org.springframework.stereotype.Component @Component classConflictName // com/foo/ConflictName.kt package com.foo import org.springframework.stereotype.Component @Component classConflictName
If we introduce these two classes directly in @SpringBootTest, the default bean naming mechanism will cause conflicts:
@SpringBootTest(
classes = [BarService::class, com.bar.ConflictName::class, com.foo.ConflictName::class, FooService::class]
)
class DemoApplicationTests {
// ...
}
At this point, the Spring container throws BeanDefinitionOverrideException because it tries to register two beans named 'conflictName'. Interestingly, if @SpringBootTest does not specify the classes attribute, that is, the entire application context is loaded, and the main application class @SpringBootApplication is configured with nameGenerator = FullyQualifiedAnnotationBeanNameGenerator::class, the test can run successfully. This indicates that the problem is missing customization of the bean name generator in the test environment.
Understanding Bean Naming Mechanism and Conflicts
When the Spring framework scans components, it will generate a unique bean name for them. By default, if a class is marked with annotations such as @Component and @Service, and the bean name is not explicitly specified, Spring will use the unqualified name of the class (that is, the class name that does not include the package name) and its first letter in lowercase as the bean name. Therefore, both com.bar.ConflictName and com.foo.ConflictName will be named conflictName, causing a conflict.
FullyQualifiedAnnotationBeanNameGenerator is a Bean name generator implementation provided by Spring. It uses the fully qualified name of the class (including the package name) as the bean name. For example, com.bar.ConflictName would be named com.bar.ConflictName, and com.foo.ConflictName would be named com.foo.ConflictName. In this way, even if the class names are the same, as long as the package names are different, the uniqueness of the Bean names can be ensured, thereby avoiding conflicts.
The main application can usually specify this generator through the nameGenerator attribute in the @SpringBootApplication annotation:
@SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator::class) classDemoApplication
However, the @SpringBootTest annotation itself does not directly provide the nameGenerator attribute, which makes customizing the bean name generator in the test environment less intuitive.
Solution: Customize the bean name generator through an internal configuration class
In order to achieve the same effect as @SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator::class) in Spring Boot tests, we need to create an isolated configuration context inside the test class.
Core idea: isolated test configuration
When a test class defines a static (or internal) class annotated with @Configuration, Spring Boot's testing framework treats it as an independent configuration for the test. This means that this internal configuration class will replace (rather than enhance) the default Spring Boot application loading process. This way we have complete control over the bean definition and scanning behavior of this test.
Implementation steps and sample code
- Define internal @Configuration class: Inside the test class annotated with @SpringBootTest, create an internal class and mark it with @Configuration annotation.
- Use @ComponentScan: On this internal configuration class, use the @ComponentScan annotation.
- nameGenerator attribute: Set it to FullyQualifiedAnnotationBeanNameGenerator::class to ensure uniqueness of the bean name.
- basePackageClasses attribute: Specify any class in the package where the component to be scanned is located. This effectively limits the scope of the scan, avoids unnecessary component loading, and ensures that components under the correct package are discovered. It should be noted that basePackageClasses scans based on packages. It scans the entire package where the specified class is located.
Here is a complete example showing how to apply this solution to resolve the above mentioned Bean name conflict issue:
package com
import com.bar.BarService
import com.bar.ConflictName
import com.foo.FooService
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator
@SpringBootTest
class DemoApplicationTests {
// Define an internal configuration class that will create an independent context for this test @Configuration
@ComponentScan(
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator::class, // Use the fully qualified name as the bean name basePackageClasses = [com.foo.ConflictName::class, com.bar.ConflictName::class, BarService::class, FooService::class] // Specify the classes in the package that need to be scanned)
internal class IsolatedTestConfig
//Inject the Bean we expect
@Autowired(required = false)
var springBootApp: org.springframework.boot.SpringApplication? = null // Used to verify context isolation @Autowired(required = false)
var compFoo: com.foo.ConflictName? = null
@Autowired(required = false)
var compBar: com.bar.ConflictName? = null
@Test
fun testNamingAndIsolation() {
// Verify that the main SpringApplication object is not loaded, proving that the context is isolated Assertions.assertNull(springBootApp)
// Verify that components with the same name in two different packages are successfully loaded. Assertions.assertNotNull(compFoo)
Assertions.assertNotNull(compBar)
}
}
In this example:
- @Configuration and @ComponentScan on the IsolatedTestConfig class together define an independent Spring application context.
- nameGenerator = FullyQualifiedAnnotationBeanNameGenerator::class ensures that com.foo.ConflictName and com.bar.ConflictName will be registered as different Beans (com.foo.ConflictName and com.bar.ConflictName), thus avoiding conflicts.
- The basePackageClasses attribute specifies the starting packages that need to be scanned to ensure that only relevant components are loaded into this isolated test context.
Notes and key points
- Context isolation: Using the internal @Configuration class creates a completely separate Spring application context that does not load the SpringBootApplication configuration of the main application. This is verified via Assertions.assertNull(springBootApp). If your tests need to load the main application context and modify or supplement it, you should consider using @TestConfiguration.
- The role of basePackageClasses: The basePackageClasses attribute is used to specify the baseline packages for scanning. Spring scans the packages and sub-packages in which these classes are located. This means that even if you only list a class, the entire package it is in will be scanned. Make sure that the classes you list represent all relevant packages you want to scan.
- Precise control: This approach provides precise control over the test context bean definition, and is particularly suitable for scenarios where you need to test a specific subset of components or simulate specific bean behavior in your test.
- Readability and maintainability: Inlining test configuration into the test class can improve the readability of the test code because all relevant configurations are gathered together.
Summarize
Handling bean name conflicts in Spring Boot integration tests is a common problem that can be effectively solved by customizing the bean name generator. By defining a @Configuration configuration class inside the test class and combining it with the @ComponentScan annotation, we can flexibly specify the nameGenerator as FullyQualifiedAnnotationBeanNameGenerator and use basePackageClasses to precisely control the component scan range. This approach not only resolves bean naming conflicts, but also creates an isolated and highly controllable context for testing, thereby improving the robustness and reliability of the tests.
The above is the detailed content of Customize the bean name generator in Spring Boot tests to resolve naming conflicts. For more information, please follow other related articles on the PHP Chinese website!
Hot AI Tools
Undress AI Tool
Undress images for free
AI Clothes Remover
Online AI tool for removing clothes from photos.
Undresser.AI Undress
AI-powered app for creating realistic nude photos
ArtGPT
AI image generator for creative art from text prompts.
Stock Market GPT
AI powered investment research for smarter decisions
Hot Article
Popular tool
Notepad++7.3.1
Easy-to-use and free code editor
SublimeText3 Chinese version
Chinese version, very easy to use
Zend Studio 13.0.1
Powerful PHP integrated development environment
Dreamweaver CS6
Visual web development tools
SublimeText3 Mac version
God-level code editing software (SublimeText3)
Hot Topics
20522
7
13634
4
How to configure Spark distributed computing environment in Java_Java big data processing
Mar 09, 2026 pm 08:45 PM
Spark cannot run in local mode, ClassNotFoundException: org.apache.spark.sql.SparkSession. This is the most common first step of getting stuck: even the dependencies are not correct. Only spark-core_2.12 is written in Maven, but spark-sql_2.12 is not added. SparkSession crashes as soon as it is built. The Scala version must strictly match the official Spark compiled version - Spark3.4.x uses Scala2.12 by default. If you use spark-sqljar of 2.13, the class loader cannot directly find the main class. Practical advice: Go to mvnre
How to safely map user-entered weekday string to integer value and implement date offset operation in Java
Mar 09, 2026 pm 09:43 PM
This article introduces a concise and maintainable way to map the weekday string (such as "Monday") to the corresponding serial number (1-7), and use the modulo operation to realize the forward and backward offset of any number of days (such as Monday plus 4 days to get Friday), avoiding lengthy if chains and hard-coded logic.
What is exception masking (Suppressed Exceptions) in Java_Multiple resource shutdown exception handling
Mar 10, 2026 pm 06:57 PM
What is SuppressedException: It is not "swallowed", but actively archived by the JVM. SuppressedException is not an exception loss, but the JVM quietly attaches the secondary exception to the main exception under the premise that "only one exception must be thrown" for you to verify afterwards. It is automatically triggered by the JVM in only two scenarios: one is that the resource closure in try-with-resources fails, and the other is that you manually call addSuppressed() in finally. The key difference is: the former is fully automatic and safe; the latter requires you to keep it to yourself, and it can be written as shadowing if you are not careful. try-
How to use Homebrew to install Java on Mac_A must-have Java tool chain for developers
Mar 09, 2026 pm 09:48 PM
Homebrew installs the latest stable version of openjdk (such as JDK22) by default, not the LTS version; you need to explicitly execute brewinstallopenjdk@17 or brewinstallopenjdk@21 to install the LTS version, and manually configure PATH and JAVA_HOME to be correctly recognized by the system and IDE.
How to correctly implement runtime file writing in Java applications (avoiding JAR internal write failures)
Mar 09, 2026 pm 07:57 PM
After a Java application is packaged as a JAR, data cannot be written directly to the resources in the JAR package (such as test.txt) because the JAR is essentially a read-only ZIP archive; the correct approach is to write variable data to an external path (such as a user directory, a temporary directory, or a configuration-specified path).
What is the underlying principle of array expansion in Java_Java memory dynamic adjustment analysis
Mar 09, 2026 pm 09:45 PM
ArrayList.add() triggers expansion because grow() is called when size is equal to elementData.length. The first add allocates 10 capacity, and subsequent expansion is 1.5 times and not less than the minimum requirement, relying on delayed initialization and System.arraycopy optimization.
Complete tutorial on reading data from file and initializing two-dimensional array in Java
Mar 09, 2026 pm 09:18 PM
This article explains in detail how to load an integer sequence in an external text file into a Java two-dimensional array according to a specified row and column structure (such as 2500×100), avoiding manual assignment or index out-of-bounds, and ensuring accurate data order and robust and reusable code.
A concise method in Java to compare whether four byte values are equal and non-zero
Mar 09, 2026 pm 09:40 PM
This article introduces several professional solutions for efficiently and safely comparing multiple byte type return values (such as getPlayer()) in Java to see if they are all equal and non-zero. We recommend two methods, StreamAPI and logical expansion, to avoid Boolean and byte mis-comparison errors.





