DEV Community

Abhishek Tiwari
Abhishek Tiwari

Posted on

Spring Boot Learning Series – Part 1: Understanding Dependency Injection

Image description

🔌 What is Dependency Injection (DI)?

Dependency Injection is a design pattern where the dependencies (objects your class needs to work) are provided to the class, instead of the class creating them itself.

🚫 Without DI:

public class Car {
    private Engine engine = new Engine(); // tightly coupled
}
Enter fullscreen mode Exit fullscreen mode

✅ With DI:

public class Car {
    private Engine engine;

    public Car(Engine engine) { // injected from outside
        this.engine = engine;
    }
}
Enter fullscreen mode Exit fullscreen mode

🌱 How DI Works in Spring Boot

  • Dependency Injection means Spring gives your class what it needs, instead of you writing code to create those things yourself.
  • Spring Boot has a built-in system called the IoC Container (ApplicationContext) that manages your objects (called beans) and connects them automatically.
  • This makes your code cleaner, easier to change, and easier to test.

🔁 IoC vs 🔌 DI

Concept Description
Inversion of Control (IoC) A general principle where control of object creation and flow is inverted — instead of you creating objects, a container/framework does it for you.
Dependency Injection (DI) specific implementation of IoC where dependencies are provided (injected) to a class, rather than the class creating them itself.

🤝 Relationship:

  • DI is one way to achieve IoC.
  • Spring uses IoC Container to inject dependencies (DI) into your classes.

Real-life analogy:

Imagine you’re baking a cake. Instead of making your own eggs, sugar, and flour from scratch, a chef (Spring) delivers these ingredients to your kitchen exactly when you need them.

Why use DI?

  • You don’t hardcode dependencies, so you can swap or change implementations easily.
  • It promotes loose coupling between classes.
  • It makes unit testing easier because you can inject mocks or stubs.

Common ways to inject dependencies in Spring Boot:

1. Field Injection (Not recommended for production but simple)

@Component
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void registerUser(User user) {
        userRepository.save(user);
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Spring injects UserRepository instance into the field.

2. Constructor Injection (Recommended!)

@Component
public class UserService {

    private final UserRepository userRepository;

    @Autowired  // Optional on single constructor since Spring 4.3+
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(User user) {
        userRepository.save(user);
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Spring injects UserRepository via constructor.
  • Easier to test and better for immutability.

3. Setter Injection

@Component
public class UserService {

    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(User user) {
        userRepository.save(user);
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Spring calls the setter method to inject the dependency.

🔄 Techniques to Swap/Change Dependencies

1. Multiple Beans + @Qualifier

@Component("petrol")
public class PetrolEngine implements Engine {}

@Component("diesel")
public class DieselEngine implements Engine {}
Enter fullscreen mode Exit fullscreen mode
@Autowired
@Qualifier("diesel")
private Engine engine;
Enter fullscreen mode Exit fullscreen mode

2. Profile-Based Beans (@Profile)

@Component
@Profile("dev")
public class DevEngine implements Engine {}

@Component
@Profile("prod")
public class ProdEngine implements Engine {}
Enter fullscreen mode Exit fullscreen mode

Set active profile in application.properties:

spring.profiles.active=prod
Enter fullscreen mode Exit fullscreen mode

3. Custom Configuration with @Bean

@Configuration
public class EngineConfig {
    @Bean
    public Engine engine() {
        return new PetrolEngine(); // or new DieselEngine();
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Conditional Beans (@ConditionalOn...)

Use Spring Boot's conditional annotations to load a bean only under specific conditions.

The property engine.type is checked in your application.properties

@Bean
@ConditionalOnProperty(name = "engine.type", havingValue = "diesel")
public Engine dieselEngine() {
    return new DieselEngine();
}
Enter fullscreen mode Exit fullscreen mode

🧠 Summary

  • DI = Don’t create dependencies yourself, let Spring give them to you
  • Makes code loosely coupled and easier to test
  • Swap dependencies using:

    ✅ @Qualifier

    ✅ @Profile

    ✅ Custom @Bean config

    ✅ Conditional beans

Top comments (0)