Why Spring’s @Autowired Is Problematic and How Constructor Injection Solves It

This article explains why overusing Spring's @Autowired can lead to hidden dependencies, tight coupling, NullPointerExceptions, and testing difficulties, and demonstrates how constructor injection provides clearer, safer, and more test‑friendly dependency management.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Why Spring’s @Autowired Is Problematic and How Constructor Injection Solves It

Introduction

Many newcomers love Spring's @Autowired for its simplicity, but in larger projects it can cause hidden problems.

Since Spring 4.0 the framework recommends constructor injection over blind use of @Autowired.

1. Implicit dependencies hide relationships

Field injection hides the true dependency graph, making the code harder to understand and maintain.

@Service
public class MyService {
    @Autowired
    private MyRepository myRepository;
}

Using constructor injection makes dependencies explicit:

@Service
public class MyService {
    private final MyRepository myRepository;

    // constructor injection
    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }
}

Dependencies are clear.

Testing becomes easier because mocks can be passed via the constructor.

2. Strong coupling to concrete implementations

Injecting a concrete class ties the service to that implementation, violating the principle of programming to an interface.

@Service
public class MyService {
    @Autowired
    private SpecificRepository specificRepository;
}

Inject an interface instead and configure the concrete bean separately:

@Service
public class MyService {
    private final Repository repository;

    public MyService(Repository repository) {
        this.repository = repository;
    }
}
@Configuration
public class RepositoryConfig {
    @Bean
    public Repository repository() {
        return new SpecificRepository();
    }
}

Implementation can be swapped without changing service code.

Aligns with interface‑driven design.

3. Risk of NullPointerException

If the container has not injected the field before the bean is used, a NullPointerException occurs.

@Service
public class MyService {
    @Autowired
    private MyRepository myRepository;

    public void doSomething() {
        myRepository.save(); // may throw NPE
    }
}

Constructor injection guarantees that the dependency is non‑null at object creation:

@Service
public class MyService {
    private final MyRepository myRepository;

    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void doSomething() {
        myRepository.save();
    }
}

4. Ambiguous autowiring when multiple candidates exist

When several beans implement the same interface, plain @Autowired leads to errors.

Explicit configuration (e.g., @Primary or @Qualifier) solves the problem but adds complexity.

Constructor injection combined with explicit bean definition keeps the code clean.

@Configuration
public class RepositoryConfig {
    @Bean
    public Repository repository() {
        return new SpecificRepository();
    }
}

5. Unit testing becomes painful

Field injection prevents easy injection of mock objects, making tests hard to write.

public class MyServiceTest {
    @Test
    public void testDoSomething() {
        MyRepository mockRepository = mock(MyRepository.class);
        MyService myService = new MyService(mockRepository);
        // test logic
    }
}

Conclusion

Constructor injection provides clear dependencies, reduces coupling, avoids NPEs, simplifies bean selection, and makes unit testing straightforward. @Autowired can still be used in limited scenarios, but the recommended practice is to prefer constructor injection.

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.

javaspringdependency-injectionConstructor InjectionAutowired
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

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.