10 Outdated Spring Boot Patterns and Their Modern Replacements

This article details ten deprecated Spring Boot patterns — from field injection and @Value overuse to WebSecurityConfigurerAdapter and RestTemplate — and shows the recommended modern alternatives for Spring Boot 3.x and 4.x migrations.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
10 Outdated Spring Boot Patterns and Their Modern Replacements

1. Introduction

Spring Boot evolves rapidly. Practices once considered best practice are now deprecated, discouraged, or removed. Maintaining older Spring Boot applications likely means your codebase contains outdated patterns. Migrating from Spring Boot 2.x to 3.x and eventually 4.x involves significant API, configuration, and ecosystem convention changes.

2. Outdated Patterns and Modern Replacements

2.1 Stop Using @Autowired Field Injection

Field injection was once the most common way to inject dependencies:

@Service
public class OrderService {
  @Autowired
  private OrderRepository orderRepo;
  @Autowired
  private PaymentGateway paymentGateway;
}

Constructor injection is the recommended approach (officially recommended since Spring 4.x):

@Service
public class OrderService {
  private final OrderRepository orderRepository;
  private final PaymentGateway paymentGateway;
  public OrderService(OrderRepository orderRepository, PaymentGateway paymentGateway) {
    this.orderRepository = orderRepository;
    this.paymentGateway = paymentGateway;
  }
}

Problems with field injection:

Dependencies cannot be defined as final

Dependencies are hidden from the class constructor

Unit testing becomes more difficult

Higher coupling to the Spring container

Class can be instantiated without required dependencies

Adding more injected fields can bloat the class without revealing design issues

Constructor injection makes dependencies explicit. If a constructor requires ten different dependencies, the class likely has too many responsibilities.

2.2 Don't Use @Value for Large Configuration Objects

@Value

is still useful for injecting single configuration values:

@Value("${pack.app.host}")
private String host;
@Value("${pack.app.port}")
private Integer port;

When a service has ten to twenty related configuration properties, scattering them across fields becomes unmaintainable. Use @ConfigurationProperties instead:

@Configuration
@ConfigurationProperties(prefix = "pack.app")
@Validated
public class AppProperties {
  @NotBlank
  private String host;
  @Min(1)
  @Max(65535)
  private int port;
  @NotNull
  private Duration timeout;
}

Configuration is now centralized in a dedicated object rather than scattered across the application.

2.3 WebSecurityConfigurerAdapter No Longer Exists

This is a major Spring Security change. Old applications typically extended WebSecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .antMatchers("/api/**").permitAll()
      .anyRequest().authenticated();
  }
}
WebSecurityConfigurerAdapter

was deprecated in Spring Security 5.7 and removed in Spring Security 6.0. The modern approach defines a SecurityFilterChain bean:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
      .requestMatchers("/api/**").permitAll()
      .anyRequest().authenticated());
    return http.build();
  }
}

2.4 RestTemplate Is Becoming Legacy

RestTemplate was the standard for HTTP calls in Spring applications. The ecosystem is transitioning to newer HTTP client APIs. For synchronous calls, the recommended modern alternative is RestClient:

RestClient restClient = RestClient.create();
User user = restClient.get()
  .uri("https://api.pack.com/users/1")
  .retrieve()
  .body(User.class);

This API provides a modern fluent programming model while remaining synchronous. For reactive applications and streaming scenarios, WebClient remains appropriate. The key point: don't adopt reactive programming just because it's newer; choose the HTTP client based on your application's actual concurrency and I/O requirements.

Note: RestTemplate is fully deprecated starting from Spring Boot 4.2+.

2.5 WebMvcConfigurerAdapter Deprecated

Older Spring MVC applications may contain:

public class WebConfig extends WebMvcConfigurerAdapter {}

Due to Java 8's default interface methods, this adapter is deprecated. Now simply implement WebMvcConfigurer:

@Configuration
public class WebConfig implements WebMvcConfigurer {}

2.6 javax.* → jakarta.*

One of the major ecosystem changes in Spring Boot 3 is the Java EE namespace migration:

javax.servlet     → jakarta.servlet
javax.persistence → jakarta.persistence
javax.validation  → jakarta.validation
javax.annotation  → jakarta.annotation
javax.transaction → jakarta.transaction
javax.mail        → jakarta.mail

This is not just a superficial import change. Third-party dependencies must also be Jakarta-compatible; otherwise, classpath and compatibility issues arise. For large codebases, automated refactoring tools like OpenRewrite can assist with migration.

2.7 JUnit 4 Patterns Replaced by JUnit 5

Early Spring tests looked like:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {}

In JUnit 5, Spring extension integration is built into the modern test environment, so you can write:

@SpringBootTest
public class UserServiceTest {}

2.8 spring.factories → AutoConfiguration.imports

If you create custom Spring Boot Starters, this migration is critical. Old auto-configuration registration used: META-INF/spring.factories Modern Spring Boot uses:

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

This migration became essential starting from Spring Boot 2.7, especially when maintaining custom starters.

2.9 Use ProblemDetail for Standardized Error Responses

Many legacy applications return custom error mappings via exception handlers: return Map.of("code", 500, "msg", "xxx"); Spring 6 and Spring Boot 3 introduced support for ProblemDetail, based on RFC 7807. This provides a standardized structure for representing errors in APIs, enabling clients to handle error responses more consistently. Instead of every service inventing its own error format, applications can expose a predictable structure — especially important for microservices and distributed systems.

2.10 Virtual Threads Change the Concurrency Discussion

An interesting development is the arrival of virtual threads. Spring Boot 3.2+ supports virtual threads, enabled via configuration:

spring:
  threads:
    virtual:
      enabled: true

This allows traditional Spring MVC applications to handle significantly higher concurrency without adopting a reactive programming model.

Important architectural point: high concurrency doesn't mandate WebFlux. For many applications, Spring MVC combined with virtual threads offers a much simpler programming model. Reactive programming still has clear use cases, particularly for streaming and certain high-concurrency workloads. Adopt it because the workload demands it, not because it's trendy.

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.

MigrationSpring BootConfigurationPropertiesVirtual ThreadsDependency InjectionRestClientSpring SecurityJakarta EEJUnit 5Spring Boot 3ProblemDetail
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

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.