Constructor Based Dependency Injection is the most recommended dependency injection technique in the Spring Framework. This technique involves passing all necessary dependencies for an object as arguments to the constructor. The object is created only after all necessary dependencies have been provided.
The main reason for preferring dependency injection through the constructor is that it allows dependencies to be explicit and mandatory. This means that all dependencies necessary for an object to function correctly must be provided at object creation time, which ensures that the object is in a valid state from the start.
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
}
In this example, the ProductService
class has a dependency on ProductRepository
, which is passed as an argument in the constructor.
Property-Based Dependency Injection(@Autowired
on a variable) involves annotating a property with the @Autowired
annotation. When Spring creates an object that has a property annotated with @Autowired
, Spring looks up an instance of the corresponding dependency and assigns it to the property.
Injecting dependencies through properties can make dependencies optional, which means that the object may be in an invalid state until all dependencies are set. This can cause run-time errors and make it difficult to identify the root cause of the problem.
Let’s look at an example:
public class ProductService {
@Autowired
private ProductRepository productRepository;
}
Setter Based Dependency Injection involves annotating a method with the @Autowired annotation. When Spring creates an object that has a method annotated with @Autowired, Spring looks up an instance of the corresponding dependency and assigns it to the method parameter.
One of the main disadvantages of setter-based injection is that it can lead to objects in an inconsistent state if all required dependencies are not established. This can be problematic because the object may not function correctly if methods are used before all dependencies have been established.
Another disadvantage is that setter-based injection can make it difficult to understand the dependencies of an object in the code, since the dependencies are not explicitly specified in the constructor. This can make it more difficult to follow the flow of control through the code.
public class ProductService {
private ProductRepository productRepository;
@Autowired
public void setProductRepository(ProductRepository productRepository) {
this.productRepository = productRepository;
}
}