Spring Context ยท Boot 3
Spring Boot 3 ยท Java 21 ยท Verified Fix

BeanDefinitionOverrideException in Boot 3

Why Spring Boot 3 breaks silently-overriding bean configurations from Boot 2.x โ€” and how to resolve bean name conflicts cleanly.

Framework
Spring Boot 3.x
Runtime
Java 21 LTS
Stability
Enterprise Grade

Technical Briefing

In Spring Boot 2.x, defining two beans with the same name caused the second to silently replace the first โ€” a behavior that could hide serious misconfiguration. Spring Boot 3 disables this by default, converting silent overrides into a hard startup failure: BeanDefinitionOverrideException. This is a deliberate safety improvement that surfaces hidden bean conflicts during migration or when library auto-configurations clash with application beans.

โš  Signal Detected

exception_report.log
FATAL
org.springframework.beans.factory.support.BeanDefinitionOverrideException: 
  Invalid bean definition with name 'dataSource' defined in 
  com.example.config.DataSourceConfig: 
  
  Cannot register bean definition [Root bean: class [com.zaxxer.hikari.HikariDataSource]]
  since there is already [Root bean: class [org.apache.tomcat.jdbc.pool.DataSource]] 
  bound.
  
  Action: Consider renaming one of the beans or enabling overriding by setting 
  spring.main.allow-bean-definition-overriding=true

โ—Ž Trace Analysis

Multiple @Configuration classes are producing @Beans with the same name โ€” either because the application defines a bean that conflicts with a library's auto-configured bean, or because two configurations in a large codebase accidentally share a bean name. Spring Boot 3's stricter default makes this an application startup failure rather than a silent runtime surprise.

โœฆ Remediation Plan

  1. Rename the conflicting bean with a unique, descriptive name (preferred: always the first option).

  2. Use @ConditionalOnMissingBean so your custom bean is only registered if no other bean of that type exists.

  3. Use @Primary to signal which bean should be injected by default when multiple candidates exist.

  4. Add @Qualifier to injection sites to select a specific bean by name.

  5. Setting spring.main.allow-bean-definition-overriding=true restores Boot 2 behavior but is a last resort โ€” it re-enables silent overrides.

Production Implementation
SafeJava 21
// โŒ CONFLICT โ€” two beans named 'dataSource' at startup
class="hi-ann">@Configuration
public class AppConfig {
    class="hi-ann">@Bean
    public DataSource dataSource() { // Name: "dataSource"
        return new HikariDataSource(hikariConfig());
    }
}

// โœ… FIX 1: Unique naming
class="hi-ann">@Configuration
public class AppConfig {
    class="hi-ann">@Bean("appDataSource")
    public DataSource dataSource() { ... }
}

// โœ… FIX 2: @ConditionalOnMissingBean (Library-safe override pattern)
class="hi-ann">@Configuration
public class AppConfig {
    class="hi-ann">@Bean
    class="hi-ann">@ConditionalOnMissingBean(DataSource.class) // Only register if nothing else provides one
    public DataSource dataSource() { ... }
}

// โœ… FIX 3: @Primary (Preferred injection candidate)
class="hi-ann">@Bean
class="hi-ann">@Primary
public DataSource primaryDataSource() { ... }

class="hi-ann">@Bean("secondaryDataSource")
public DataSource secondaryDataSource() { ... }

// Injection uses @Primary automatically:
// @Autowired DataSource ds; โ†’ gets primaryDataSource

// โš ๏ธ ESCAPE HATCH (Boot 2 compatibility only โ€” avoid in new code)
# application.properties
spring.main.allow-bean-definition-overriding=true

โŸ Engineering Deep-Dive

Bean Naming Rules

By default, a class="hi-ann">@Bean method's name is the method name. A class annotated with class="hi-ann">@Component, class="hi-ann">@Service, or class="hi-ann">@Repository uses the decapitalized class name. When two beans share the same name in the same ApplicationContext, Boot 3 fails fast at startup rather than allowing a random winner.

Auto-Configuration Conflicts

The most common source of this exception in Boot 3 migrations is the application defining a bean that Boot's own auto-configuration also tries to provide โ€” e.g., a custom DataSource clashing with DataSourceAutoConfiguration. Use class="hi-ann">@ConditionalOnMissingBean in your configuration to yield to auto-configuration, or use spring.autoconfigure.exclude to disable the conflicting auto-configuration entirely.

Bean Naming Conventions at Scale

In large codebases with many shared modules, prefix bean names with the module name to avoid collisions: class="hi-ann">@Bean("payments.dataSource"), class="hi-ann">@Bean("inventory.dataSource"). This is especially important when composing multiple Spring modules into a single application context.

โ—‡ Elite Standards

  1. Engineering Rule

    Never use spring.main.allow-bean-definition-overriding=true in new projects โ€” it trades a startup error for a silent runtime misconfiguration.

  2. Engineering Rule

    Prefer @ConditionalOnMissingBean in all shared library configurations to make them override-safe by design.

  3. Engineering Rule

    Add a startup smoke test to your CI pipeline that verifies ApplicationContext loads successfully โ€” catches bean conflicts before they reach production.

FAQ

What causes BeanDefinitionOverrideException in Boot 3 in Spring Boot 3?
Multiple @Configuration classes are producing @Beans with the same name โ€” either because the application defines a bean that conflicts with a library's auto-configured bean, or because two configurations in a large codebase accidentally share a bean name. Spring Boot 3's stricter default makes this an application startup failure rather than a silent runtime surprise.
How do I fix BeanDefinitionOverrideException in Boot 3?
Rename the conflicting bean with a unique, descriptive name (preferred: always the first option). Use @ConditionalOnMissingBean so your custom bean is only registered if no other bean of that type exists. Use @Primary to signal which bean should be injected by default when multiple candidates exist. Add @Qualifier to injection sites to select a specific bean by name. Setting spring.main.allow-bean-definition-overriding=true restores Boot 2 behavior but is a last resort โ€” it re-enables silent overrides.
Best practice #1 for preventing Spring Context ยท Boot 3 errors?
Never use spring.main.allow-bean-definition-overriding=true in new projects โ€” it trades a startup error for a silent runtime misconfiguration.
Best practice #2 for preventing Spring Context ยท Boot 3 errors?
Prefer @ConditionalOnMissingBean in all shared library configurations to make them override-safe by design.
Best practice #3 for preventing Spring Context ยท Boot 3 errors?
Add a startup smoke test to your CI pipeline that verifies ApplicationContext loads successfully โ€” catches bean conflicts before they reach production.

Feedback

Live
ML

M. Leachouri

Founder & Chief Architect

"I built Kodivio because professional tools shouldn't come at the cost of your privacy. Our mission is to provide enterprise-grade utilities that process data exclusively in your browser."

M. Leachouri is an Expert Web Developer, Data Scientist Engineer, and Systems Architect with a deep specialization in DevOps and Cybersecurity. With over a decade of experience building scalable distributed systems and Zero-Trust architectures, he engineered Kodivio to bridge the gap between high-performance computing and absolute user sovereignty.

Verified Expert
Certified Architect
Full Profile & Mission โ†’