There are three possible ways of DI in Spring
- Constructor-based: should be used for mandatory dependencies. In constructor, we should assign constructor args to final member fields.
- Setter-based: Should be used for optional dependencies.
- Field-based: Spring discourages the use of this because it would possibly hide mandatory fields from outside which would otherwise be assigned in the constructor. This would take away the advantage of properly initialized POJO, specially if intended to use outside of Spring container. Even though, we are mostly using field based injection in this series of tutorials to simplify the concept we want to deliver, we suggest the developers to always avoid using field-based DI in real project scenarios.
Examples
package com.logicbig.example.service;
public class OrderService {
public String getOrderDetails(String orderId) {
return "Order details for order id=" + orderId;
}
}
Constructor Based DI
package com.logicbig.example;
import com.logicbig.example.service.OrderService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConstBasedDI {
@Bean
public OrderService orderService() {
return new OrderService();
}
@Bean
public OrderServiceClient orderServiceClient() {
return new OrderServiceClient(orderService());
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConstBasedDI.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
private static class OrderServiceClient {
private OrderService orderService;
// @Autowired is not needed
OrderServiceClient(OrderService orderService) {
this.orderService = orderService;
}
public void showPendingOrderDetails() {
System.out.println(orderService.getOrderDetails("100"));
}
}
} OutputOrder details for order id=100
Constructor Based DI with Component Scan
Following example shows Constructor Based DI with @ComponentScan:
package com.logicbig.example.scan;
import com.logicbig.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
@ComponentScan({"com.logicbig.example.scan"})
public class ConstBasedDIWithScan {
@Bean
public OrderService orderService() {
return new OrderService();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConstBasedDIWithScan.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
@Component
public static class OrderServiceClient {
private OrderService orderService;
@Autowired
OrderServiceClient(OrderService orderService) {
this.orderService = orderService;
}
public void showPendingOrderDetails() {
System.out.println(orderService.getOrderDetails("500"));
}
}
} OutputOrder details for order id=500
Setter Based DI
package com.logicbig.example;
import com.logicbig.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SetterBasedDI {
@Bean
public OrderService orderService() {
return new OrderService();
}
@Bean
public OrderServiceClient orderServiceClient() {
return new OrderServiceClient();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
SetterBasedDI.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
private static class OrderServiceClient {
private OrderService orderService;
@Autowired
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void showPendingOrderDetails() {
System.out.println(orderService.getOrderDetails("200"));
}
}
} OutputOrder details for order id=200
package com.logicbig.example;
import com.logicbig.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FieldBasedDI {
@Bean
public OrderService orderService() {
return new OrderService();
}
@Bean
public OrderServiceClient orderServiceClient() {
return new OrderServiceClient();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FieldBasedDI.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
private static class OrderServiceClient {
@Autowired
private OrderService orderService;
public void showPendingOrderDetails() {
System.out.println(orderService.getOrderDetails("300"));
}
}
} OutputOrder details for order id=300
Example ProjectDependencies and Technologies Used: - spring-context 6.1.2 (Spring Context)
Version Compatibility: 3.2.9.RELEASE - 6.1.2 Version compatibilities of spring-context with this example: Versions in green have been tested.
- JDK 17
- Maven 3.8.1
|