Why SpringBoot Auto‑Configuration Loading Order Matters and How to Control It

Understanding the loading order and priority of SpringBoot auto‑configuration classes is crucial because it determines conditional bean registration, prevents conflicts, and enables custom configurations to override defaults; the article explains the default hierarchy, key annotations for ordering, the new @AutoConfiguration mechanism in 2.7+, and practical debugging techniques.

Java Tech Workshop
Java Tech Workshop
Java Tech Workshop
Why SpringBoot Auto‑Configuration Loading Order Matters and How to Control It

Why loading order matters

Spring creates beans in a fixed sequence: it sorts configuration classes, parses each class, evaluates @Conditional annotations, and registers beans that satisfy the conditions. If a configuration class depends on a bean that has not yet been created, the condition fails and the class is skipped.

Loading order decides condition results

Example: configuration class A uses @ConditionalOnBean(B.class). If A is processed before B, the condition fails because B does not exist yet, so A is not loaded. Reversing the order makes the condition succeed.

Common pitfalls

Custom configuration cannot override official auto‑configuration – official auto‑configuration uses @ConditionalOnMissingBean. If the official configuration runs first and creates the default bean, the later custom configuration sees the bean already present and its condition fails.

Configuration classes depend on each other – when class A depends on B (or vice‑versa) and the dependent class loads first, @ConditionalOnBean fails, leading to NoSuchBeanDefinitionException at startup.

Multiple third‑party starters conflict – importing both mybatis-spring-boot-starter and spring-boot-starter-jdbc introduces two DataSource beans, causing duplicate definition errors. Similar conflicts occur with logging starters (logback vs log4j2) when the load order is incorrect.

Default loading rules

SpringBoot loads configuration classes in three steps:

User‑defined configuration (discovered by @ComponentScan or imported with @Import).

Auto‑configuration classes declared in spring.factories (pre‑2.7) or AutoConfiguration.imports (2.7+).

All classes are sorted by priority and processed sequentially.

Priority tiers (high to low):

User manual configuration – @Configuration classes in the main package, @Import, @ImportResource, and configurations set via SpringApplication.setSources(). These are processed before any auto‑configuration.

Auto‑configuration imported via @EnableAutoConfiguration – loaded from META-INF/spring.factories (SpringBoot <2.7) or

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

(≥2.7). Internal ordering annotations ( @AutoConfigureBefore, @AutoConfigureAfter, @AutoConfigureOrder) apply.

Default‑sorted auto‑configuration – when no explicit order is set, SpringBoot sorts by component type: core framework, web layer, data layer, utility layer, monitoring & testing.

Core annotations to control loading order

For auto‑configuration classes

@AutoConfigureOrder

– numeric priority; smaller values load earlier. Default is Ordered.LOWEST_PRECEDENCE. @AutoConfigureBefore – forces the current auto‑configuration to load before the specified class(es). The target class must be registered in the auto‑configuration list. Multiple targets are allowed. Circular dependencies cause a startup loop. @AutoConfigureAfter – opposite of @AutoConfigureBefore; ensures the current class loads after the specified class(es).

Example of highest‑priority auto‑configuration:

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class MyHighPriorityAutoConfig {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

Custom Redis auto‑configuration that must run before the official one:

@Configuration
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class MyRedisAutoConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        // custom serializer configuration …
        return template;
    }
}

JdbcTemplate auto‑configuration that depends on a DataSource:

@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyJdbcAutoConfig {
    @Bean
    @ConditionalOnBean(DataSource.class)
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

For ordinary configuration classes

@Order

– sets loading priority for regular @Configuration classes or individual @Bean methods. Semantics are identical to @AutoConfigureOrder but apply only to user‑defined configurations. @DependsOn – enforces bean creation order regardless of configuration class order.

Example with @Order:

@Configuration
@Order(1)
public class Config1 {
    @Bean
    public Bean1 bean1() {
        System.out.println("Config1 loaded, creating Bean1");
        return new Bean1();
    }
}

@Configuration
@Order(2)
public class Config2 {
    @Bean
    public Bean2 bean2(Bean1 bean1) {
        System.out.println("Config2 loaded, creating Bean2");
        return new Bean2();
    }
}

Example with @DependsOn:

@Configuration
public class DependsOnConfig {
    @Bean
    public BeanB beanB() {
        System.out.println("Creating BeanB");
        return new BeanB();
    }

    @Bean
    @DependsOn("beanB")
    public BeanA beanA() {
        System.out.println("Creating BeanA (depends on BeanB)");
        return new BeanA();
    }
}

Generic for all configuration classes

@Import

manually imports another configuration class; the imported class is processed before the current one and is not affected by @Order or auto‑configuration ordering annotations.

@Configuration
@Import(ConfigA.class)
public class Config {
    // configuration content …
}

SpringBoot 2.7+ @AutoConfiguration

Since SpringBoot 2.7 the recommended way to declare an auto‑configuration class is @AutoConfiguration, which implicitly includes @Configuration and @EnableAutoConfiguration. Registration moves from spring.factories to AutoConfiguration.imports.

Comparison:

Old (SpringBoot <2.7): use @Configuration + @EnableAutoConfiguration, register in META-INF/spring.factories.

New (≥2.7): use @AutoConfiguration, register in

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

.

Both support @AutoConfigureBefore, @AutoConfigureAfter, @AutoConfigureOrder.

Practical example:

@AutoConfiguration
@AutoConfigureBefore(RedisAutoConfiguration.class)
@ConditionalOnClass(RedisTemplate.class)
public class MyRedisAutoConfig {
    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // custom configuration …
        return new RedisTemplate<>();
    }
}

To register, add the fully‑qualified class name to AutoConfiguration.imports (one line per class):

com.example.redis.MyRedisAutoConfig

SpringBoot 2.7+ still supports the old spring.factories approach for backward compatibility. @AutoConfiguration already contains the functionality of @Configuration and @EnableAutoConfiguration, so they should not be added again.

Debugging configuration loading order

Enable debug logs

Add debug: true to application.yml. SpringBoot prints an AutoConfigurationReport that lists every auto‑configuration class, whether its conditions matched, and the exact loading order.

debug: true  # enable debug logging to view auto‑configuration details

Custom ApplicationListener

Implement a listener for ContextRefreshedEvent to print the order of all configuration classes (or beans) after the context is refreshed.

@Component
public class ConfigLoadListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        String[] beanNames = context.getBeanDefinitionNames();
        System.out.println("Configuration class/Bean loading order:");
        for (int i = 0; i < beanNames.length; i++) {
            String beanName = beanNames[i];
            if (context.getBeanDefinition(beanName).getBeanClassName() != null &&
                context.getBeanDefinition(beanName).getBeanClassName().endsWith("Config")) {
                System.out.println((i + 1) + ". " + beanName);
            }
        }
    }
}

IDE breakpoint debugging

Set breakpoints on @Bean methods of the auto‑configuration classes you suspect. Run the application in debug mode; the order in which breakpoints are hit reveals the actual loading sequence, and you can inspect the evaluation of condition annotations at each step.

Typical interview questions

Loading order of SpringBoot auto‑configuration classes – three tiers: (1) user‑defined configuration (highest), (2) auto‑configuration imported via @EnableAutoConfiguration, (3) internally default‑sorted auto‑configuration. Within a tier ordering can be controlled with @AutoConfigureBefore, @AutoConfigureAfter, @AutoConfigureOrder or @Order / @DependsOn.

Why can a custom bean override an official auto‑configuration bean? – user configuration has higher priority and runs first; official auto‑configuration uses @ConditionalOnMissingBean, which is skipped when the custom bean already exists.

Difference between @AutoConfigureAfter and @DependsOn – @AutoConfigureAfter controls the loading order of auto‑configuration classes only; @DependsOn forces a specific bean to be created after another bean, regardless of class order.

Optimizations introduced in SpringBoot 2.7 – introduction of @AutoConfiguration and AutoConfiguration.imports, providing clearer semantics and more stable loading.

How to debug auto‑configuration loading problems – enable debug logs, implement a custom ApplicationListener, or use IDE breakpoints on @Bean methods.

Conclusion

User configuration > auto‑configuration – custom beans win over defaults.

Control order with the three‑weapon set ( @AutoConfigureBefore, @AutoConfigureAfter, @AutoConfigureOrder) for auto‑configuration classes, and with @Order / @DependsOn for ordinary configuration.

SpringBoot 2.7+ encourages @AutoConfiguration and AutoConfiguration.imports for a cleaner separation.

When problems arise, remember the chain: wrong order → condition failure → bean missing/duplicate → startup error, and use debug logs or breakpoints to locate the offending class.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DebuggingAnnotationsSpringBootAutoConfigurationBeanLoadingSpringBoot2.7
Java Tech Workshop
Written by

Java Tech Workshop

Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.