Course topics

By WebNest Studio Engineering Team

Spring Boot Tutorial

Spring Boot Auto-Configuration

Auto-configuration is the mechanism that makes Spring Boot feel "magic" the first time you use it: add spring-boot-starter-data-jpa and a DataSource, and a fully working JPA setup — connection pool, EntityManagerFactory, transaction manager — appears without you writing a single @Bean method. Understanding how this actually works removes the magic and replaces it with a predictable rule set.

@EnableAutoConfiguration and Conditional Beans

@EnableAutoConfiguration (bundled inside @SpringBootApplication) tells Spring Boot to scan a list of auto-configuration classes registered in the classpath (via META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports in modern versions) and conditionally apply each one. Each auto-configuration class is guarded by conditional annotations that decide, at startup, whether it should activate.

  • @ConditionalOnClass — activates only if a specific class is present on the classpath (e.g. only configure JPA support if EntityManager.class exists).
  • @ConditionalOnMissingBean — activates only if you have not already defined your own bean of that type, so your explicit configuration always wins over the default.
  • @ConditionalOnProperty — activates only if a specific application property is set to a given value.
  • @ConditionalOnWebApplication — activates only inside a web application context, not a plain CLI application.

Overriding Auto-Configuration

Because most auto-configuration is guarded by @ConditionalOnMissingBean, you can override any default simply by defining your own bean of the same type in a @Configuration class — Spring Boot's own bean backs off automatically. This "sensible defaults, easy to override" pattern is the core design philosophy behind the entire framework.

Inspecting What Auto-Configured

When auto-configuration behaves unexpectedly, enabling debug logging (--debug flag or debug=true in application.properties) prints an auto-configuration report at startup listing every candidate class as "Positive match" or "Negative match," along with the exact condition that decided it — this is the single most useful diagnostic tool for auto-configuration issues.

Customize First, Replace Last

There are three levels of control, and the lightest one that works is usually the right one:

  • Properties. Most auto-configured beans read spring.* properties, such as spring.jackson.*, spring.datasource.* or server.*. Try these first.
  • Customizer beans. Many auto-configurations accept customizers, such as JsonMapperBuilderCustomizer for Jackson or WebServerFactoryCustomizer for the embedded server. A customizer adjusts the bean Spring Boot builds, so all the other defaults and the spring.* properties keep working.
  • Your own bean. Declaring a bean of the same type makes the auto-configured one back off completely. You then own every setting, and the related properties and customizers stop applying. Use this only when you truly need full control.

Excluding an Auto-Configuration

Sometimes a library on the classpath triggers configuration you do not want, for example a DataSource being configured in a service that has no database. Exclude it with @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) or the property spring.autoconfigure.exclude. Excluding is better than adding a dummy bean, because the intent is explicit and shows in the debug report.

Jackson in Spring Boot 4

Spring Boot 4 auto-configures Jackson 3, whose classes live in the tools.jackson package. The main bean is a JsonMapper rather than the Jackson 2 ObjectMapper from com.fasterxml.jackson.databind, which older tutorials override. Jackson 3 also writes java.time values such as LocalDate as ISO strings ("2026-11-30") by default, so the old JavaTimeModule and WRITE_DATES_AS_TIMESTAMPS setup is no longer needed.

Examples

Customizing Spring Boot's JsonMapper instead of replacing it (tested on Spring Boot 4.1.1)

Java
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tools.jackson.databind.SerializationFeature;

@Configuration
public class JsonConfig {

    // Adjusts the JsonMapper that Spring Boot builds, instead of replacing it.
    @Bean
    JsonMapperBuilderCustomizer prettyJsonWithoutNulls() {
        return builder -> builder
                .enable(SerializationFeature.INDENT_OUTPUT)
                .changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL));
    }
}

@RestController
public class InvoiceController {

    public record Invoice(String number, LocalDate dueDate, BigDecimal amount, String note) {}

    @GetMapping("/api/invoice")
    public Invoice invoice() {
        return new Invoice("INV-1042", LocalDate.of(2026, 11, 30), new BigDecimal("1499.00"), null);
    }
}
Output
GET /api/invoice
{
  "number" : "INV-1042",
  "dueDate" : "2026-11-30",
  "amount" : 1499.00
}
(pretty-printed, and the null "note" field is left out)

Replacing the bean completely, and what --debug reports

Java
@Configuration
public class OwnMapperConfig {

    // Replaces Spring Boot's JsonMapper completely. Boot's version backs off,
    // and customizers and spring.jackson.* properties no longer apply.
    @Bean
    JsonMapper jsonMapper() {
        return JsonMapper.builder().build();
    }
}

// Run with: java -jar app.jar --debug
Output
GET /api/invoice
{"number":"INV-1042","dueDate":"2026-11-30","amount":1499.00,"note":null}
(the customizer above no longer runs, so the output is compact and includes nulls)

From the CONDITIONS EVALUATION REPORT, under "Negative matches":
   JacksonAutoConfiguration#jacksonJsonMapper:
      Did not match:
         - @ConditionalOnMissingBean (types: tools.jackson.databind.json.JsonMapper; SearchStrategy: all) found beans of type 'tools.jackson.databind.json.JsonMapper' jsonMapper (OnBeanCondition)

Common Mistakes

  • Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working.
  • Copying a Spring Boot 2/3 ObjectMapper override into a Spring Boot 4 project. Boot 4 auto-configures a Jackson 3 JsonMapper from tools.jackson, so a com.fasterxml ObjectMapper bean does not replace it.
  • Assuming auto-configuration always "just works" and skipping the --debug report when something behaves unexpectedly, instead of guessing.
  • Defining a bean of a slightly different type than Spring Boot expects, so @ConditionalOnMissingBean does not detect it and you end up with two competing beans.
  • Believing @EnableAutoConfiguration scans your own code for components — it only evaluates registered auto-configuration classes, not your @Component classes (that is @ComponentScan's job).

Exercise

Using the lesson's Customizing Spring Boot's JsonMapper instead of replacing it (tested on Spring Boot 4.1.1) example, create a small implementation or design sketch that demonstrates @EnableAutoConfiguration conditionally applies pre-built configuration classes based on what is on the classpath and what beans already exist.. Add a test case or scenario that would catch Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working., and describe the expected result.

Show hints
  • Start with @EnableAutoConfiguration and Conditional Beans and compare your approach with Customizing Spring Boot's JsonMapper instead of replacing it (tested on Spring Boot 4.1.1). Identify the decision or behavior the lesson recommends.
  • Walk through your scenario step by step. Confirm that it follows @EnableAutoConfiguration conditionally applies pre-built configuration classes based on what is on the classpath and what beans already exist. and that it would catch the failure described by Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working..

Quick quiz

1. Which choice is a mistake to avoid in Spring Boot Auto-Configuration?

  • A. Copying a Spring Boot 2/3 ObjectMapper override into a Spring Boot 4 project. Boot 4 auto-configures a Jackson 3 JsonMapper from tools.jackson, so a com.fasterxml ObjectMapper bean does not replace it.
  • B. @EnableAutoConfiguration conditionally applies pre-built configuration classes based on what is on the classpath and what beans already exist.
  • C. Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working.
Show answer

C. Avoid this approach: Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working. The lesson recommends: @EnableAutoConfiguration conditionally applies pre-built configuration classes based on what is on the classpath and what beans already exist.

Interview questions

A teammate is about to make this mistake: Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working. How would you diagnose and correct it using the lesson's guidance?

Show answer

@EnableAutoConfiguration conditionally applies pre-built configuration classes based on what is on the classpath and what beans already exist. Apply this in @EnableAutoConfiguration and Conditional Beans; the example Customizing Spring Boot's JsonMapper instead of replacing it (tested on Spring Boot 4.1.1) shows one way to do it. Avoid Replacing an auto-configured bean (such as the JsonMapper) when a customizer or a spring.* property would do. The replacement silently drops every other default and stops the related properties from working. and explain how your implementation or design prevents that failure.

Key Points to Remember

  • @EnableAutoConfiguration conditionally applies pre-built configuration classes based on what is on the classpath and what beans already exist.
  • @ConditionalOnClass, @ConditionalOnMissingBean, and @ConditionalOnProperty are the most common conditions guarding auto-configuration.
  • Defining your own @Bean of the same type is the standard way to override an auto-configured default.
  • Run with --debug to print the auto-configuration match/no-match report when behavior is unclear.
  • Prefer properties, then customizer beans, and replace a bean only when you need full control.
  • Exclude unwanted auto-configuration with exclude = … or spring.autoconfigure.exclude.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering