Spring Core Dependency Injection: Step-by-Step Guide with Complete Example
Dependency Injection (DI) is a key concept in Spring Core that promotes loose coupling between components. This guide covers IoC container, types of DI, bean configuration, and bean lifecycle, with a step-by-step complete example to help you implement these concepts in a real-world application.
1. Understanding Spring’s IoC Container
The Inversion of Control (IoC) container is the foundation of the Spring framework. It manages the lifecycle and configuration of objects (beans) and their dependencies. The IoC container:
- Instantiates beans.
- Resolves and injects dependencies.
- Configures bean lifecycle callbacks.
Types of IoC Containers in Spring:
- BeanFactory: The basic IoC container for simple applications.
- ApplicationContext: An advanced container with support for AOP, internationalization, and event handling.
2. Types of Dependency Injection
Spring supports two main types of dependency injection:
- Constructor Injection
- Setter Injection
a. Constructor Injection
Dependencies are provided via the constructor at the time of object creation.
@Component
public class Car {
private Engine engine;
@Autowired
public Car(Engine engine) {
this.engine = engine;
}
public void drive() {
engine.start();
System.out.println("Car is running...");
}
}
b. Setter Injection
Dependencies are provided via setter methods after the bean is instantiated.
@Component
public class Car {
private Engine engine;
@Autowired
public void setEngine(Engine engine) {
this.engine = engine;
}
public void drive() {
engine.start();
System.out.println("Car is running...");
}
}
3. Beans Configuration
Beans are the backbone of Spring applications. You can configure them in two ways:
- XML-based Configuration
- Annotation-based Configuration
a. XML-based Configuration
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean for Engine -->
<bean id="engine" class="com.example.Engine"/>
<!-- Bean for Car with Constructor Injection -->
<bean id="car" class="com.example.Car">
<constructor-arg ref="engine"/>
</bean>
</beans>
b. Annotation-based Configuration
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// No explicit bean definitions are required; Spring automatically detects @Component classes.
}
4. Lifecycle of a Spring Bean
Spring beans go through several lifecycle stages:
- Instantiation: The IoC container creates the bean.
- Populate Properties: Dependencies are injected.
- Initialization: Custom initialization logic is executed (e.g., methods annotated with
@PostConstruct
). - Destruction: Resources are cleaned up (e.g., methods annotated with
@PreDestroy
).
Example:
@Component
public class MyBean {
@PostConstruct
public void init() {
System.out.println("Bean initialized.");
}
@PreDestroy
public void cleanup() {
System.out.println("Bean destroyed.");
}
}
Complete Step-by-Step Example
This section demonstrates how to set up a Spring application with DI using Eclipse or IntelliJ IDEA.
Step 1: Create a Maven Project
- Open Eclipse or IntelliJ IDEA.
- Create a new Maven project.
- Add the following dependencies in your
pom.xml
:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.30</version>
</dependency>
</dependencies>
Step 2: Create Classes
Engine.java
@Component
public class Engine {
public void start() {
System.out.println("Engine started.");
}
}
Car.java
@Component
public class Car {
private Engine engine;
@Autowired
public Car(Engine engine) {
this.engine = engine;
}
public void drive() {
engine.start();
System.out.println("Car is driving...");
}
}
Step 3: Configure Spring Application
AppConfig.java
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
Step 4: Write Main Method
MainApp.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Car car = context.getBean(Car.class);
car.drive();
}
}
Step 5: Run the Application
- Right-click on the
MainApp
class and select Run As -> Java Application. - Output:
Engine started.
Car is driving...
Best Practices
- Prefer Constructor Injection for mandatory dependencies.
- Use @ComponentScan to simplify bean discovery.
- Manage resources effectively with
@PostConstruct
and@PreDestroy
. - Use Singleton Scope for stateless beans and Prototype Scope for stateful beans.