Spring Boot
DataSource
Bean Overriding
Spring Boot 2.1
Java Configuration

DataSource bean overriding in spring boot 2.1

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Spring Boot 2.1 changed bean overriding behavior in a way that surprised many applications during upgrades. DataSource configuration is a common place where this shows up, because developers often mix Boot auto-configuration, custom beans, test overrides, and multiple database setups without realizing which rule is actually winning.

What Changed in Spring Boot 2.1

Before Spring Boot 2.1, accidental bean name collisions were easier to miss. Starting with 2.1, bean definition overriding is disabled by default, which means duplicate bean names now fail fast with BeanDefinitionOverrideException.

That does not mean you cannot customize the DataSource. It means you should do it explicitly instead of relying on silent replacement.

The Simplest Custom DataSource

If you define your own DataSource bean, Spring Boot backs off from creating the default auto-configured one. That is the usual and recommended customization path.

java
1package com.example.demo;
2
3import javax.sql.DataSource;
4
5import com.zaxxer.hikari.HikariDataSource;
6import org.springframework.boot.context.properties.ConfigurationProperties;
7import org.springframework.context.annotation.Bean;
8import org.springframework.context.annotation.Configuration;
9
10@Configuration
11public class DataSourceConfig {
12
13    @Bean
14    @ConfigurationProperties("app.datasource")
15    public DataSource dataSource() {
16        return new HikariDataSource();
17    }
18}

With matching properties:

properties
app.datasource.jdbc-url=jdbc:mysql://localhost:3306/app
app.datasource.username=app
app.datasource.password=secret

In this setup, you are not overriding a Boot bean by collision. You are providing the bean yourself, and Boot backs off correctly.

When Name Collisions Cause the Error

The upgrade problem usually appears when two beans with the same name exist. That can happen with multiple configuration classes, imported test configs, or copy-pasted @Bean methods.

Example of a risky setup:

java
1@Configuration
2public class AppConfig {
3
4    @Bean
5    public DataSource dataSource() {
6        return new HikariDataSource();
7    }
8}
9
10@Configuration
11public class AnotherConfig {
12
13    @Bean
14    public DataSource dataSource() {
15        return new HikariDataSource();
16    }
17}

In Boot 2.1, this fails instead of silently replacing one bean with the other. That is usually a good failure because it forces you to clarify intent.

Multiple DataSource Beans

If you genuinely need more than one DataSource, give them different bean names and mark one as @Primary.

java
1package com.example.demo;
2
3import javax.sql.DataSource;
4
5import com.zaxxer.hikari.HikariDataSource;
6import org.springframework.boot.context.properties.ConfigurationProperties;
7import org.springframework.context.annotation.Bean;
8import org.springframework.context.annotation.Configuration;
9import org.springframework.context.annotation.Primary;
10
11@Configuration
12public class MultiDataSourceConfig {
13
14    @Bean
15    @Primary
16    @ConfigurationProperties("app.datasource.main")
17    public DataSource mainDataSource() {
18        return new HikariDataSource();
19    }
20
21    @Bean
22    @ConfigurationProperties("app.datasource.reporting")
23    public DataSource reportingDataSource() {
24        return new HikariDataSource();
25    }
26}

This is clearer than trying to "override" one bean with another.

The Override Flag Exists, but Use It Carefully

If you truly need the old behavior, Boot 2.1 provides:

properties
spring.main.allow-bean-definition-overriding=true

This makes collisions legal again, but it also reintroduces ambiguity. In most application code, that flag is a last resort, not the first fix. It is better to rename beans, use @Primary, or remove redundant configuration.

Test-Specific Overrides

Tests are a common case where developers want a different DataSource. Prefer explicit test configuration rather than broad override flags.

java
1package com.example.demo;
2
3import javax.sql.DataSource;
4
5import org.springframework.boot.test.context.TestConfiguration;
6import org.springframework.context.annotation.Bean;
7import org.springframework.context.annotation.Primary;
8import org.springframework.jdbc.datasource.DriverManagerDataSource;
9
10@TestConfiguration
11public class TestDataSourceConfig {
12
13    @Bean
14    @Primary
15    public DataSource testDataSource() {
16        DriverManagerDataSource ds = new DriverManagerDataSource();
17        ds.setDriverClassName("org.h2.Driver");
18        ds.setUrl("jdbc:h2:mem:testdb");
19        ds.setUsername("sa");
20        ds.setPassword("");
21        return ds;
22    }
23}

That communicates intent clearly and keeps production configuration predictable.

How to Decide the Right Approach

Use this rule set:

  • Define one explicit DataSource bean when you want full control.
  • Use different names plus @Primary when you need multiple datasources.
  • Use test-specific config for test replacement.
  • Avoid global bean override flags unless you have a controlled legacy reason.

That approach scales better than silent bean replacement.

Common Pitfalls

The most common mistake is assuming Boot 2.1 stopped allowing custom DataSource beans. It did not. The real issue is duplicate bean definitions with the same name. Another mistake is enabling bean overriding globally instead of fixing ambiguous configuration. Teams also forget @Primary when introducing a second DataSource, which creates injection ambiguity even when bean names are distinct. In tests, broad overrides can also leak behavior that is very different from production wiring.

Summary

  • Spring Boot 2.1 disables bean definition overriding by default.
  • Defining your own DataSource bean is still a normal and supported customization path.
  • Real problems usually come from duplicate bean names, not from DataSource customization itself.
  • Use distinct bean names and @Primary for multiple datasources.
  • Treat spring.main.allow-bean-definition-overriding=true as an exception, not the default fix.

Course illustration
Course illustration

All Rights Reserved.