Dependency Injection (DI) is a fundamental concept in the Spring Framework. It's a design pattern that allows objects to be loosely coupled by externalizing the dependencies and allowing the container to manage them.
In the Spring Framework, DI is achieved through Inversion of Control (IoC). In other words, instead of objects creating their own dependencies, they rely on an external container to provide those dependencies.
Here's an example of how to use DI in Spring:
public class MyService {
private final MyRepository repository;
public MyService(MyRepository repository) {
this.repository = repository;
}
public void doSomething() {
// use the repository here
}
}
In this example, MyService has a dependency on MyRepository. Instead of creating the MyRepository instance itself, it relies on an external container to provide it through constructor injection.
To configure the container, you can use annotations like @ComponentScan, @Component, @Autowired, @Qualifier, and others. Here's an example of how to configure a Spring application context with XML:
<beans>
<bean id="myRepository" class="com.example.MyRepository" />
<bean id="myService" class="com.example.MyService">
<constructor-arg ref="myRepository" />
</bean>
</beans>
In this example, the container creates a MyRepository bean and injects it into the MyService bean using constructor injection.
There are three types of Dependency Injection (DI) that can be used to inject dependencies into objects:
Here's an example of how to use each type of DI in Spring using annotations:
@Component
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
}
In this example, the MyService class has a constructor that takes a MyRepository dependency as an argument. The @Autowired annotation tells Spring to inject the MyRepository dependency into the constructor.
@Component
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}
In this example, the MyService class has a setter method that takes a MyRepository dependency as an argument. The @Autowired annotation tells Spring to inject the MyRepository dependency into the setter method.
@Component
public class MyService {
@Autowired
private MyRepository repository;
// methods here.
}
In this example, the MyService class has a field of type MyRepository. The @Autowired annotation tells Spring to inject the MyRepository dependency directly into the field.
It's worth noting that Constructor Injection is generally considered the best practice because it ensures that all dependencies are provided when the object is created, making the object fully initialized and ready to use. Setter Injection and Field Injection can be useful in certain situations, but they can also make the object more complex and harder to test.
By using DI, you can achieve loose coupling between your objects and make your code more modular and testable. You can easily swap out dependencies with mock objects or other implementations, and you can easily configure your application context to provide different dependencies based on the environment or configuration.