Conteúdo do Curso
Spring Boot Backend
Spring Boot Backend
IoC and DI
The Spring Container is the central component of the Spring Framework that manages the creation, configuration, and lifecycle of beans (objects) within an application. The Spring Container is also known as the IoC container.
A dependency refers to any class that requires other objects to be injected for it to function properly, and this chain of dependencies can go on indefinitely. Normally, to create an object with dependencies, we have to explicitly initialize it using the new
operator and specify the class.
But that’s where Spring comes in with Inversion of Control
and Dependency Injection
. The idea is that Spring takes over the responsibility of creating and managing dependencies. Instead of manually handling the setup, we simply annotate the necessary classes, and Spring automatically creates them and manages their lifecycle within its context.
One of these annotations is @Component
, which we place above the class.
BeanExample
@Component public class BeanExample { }
This approach shifts the focus away from manually managing dependencies, allowing developers to concentrate on business logic while Spring handles the infrastructure tasks related to object creation and dependency management.
How the Spring container works?
When the application starts, the Spring Container is initialized. It begins by scanning the classes for annotations like @Component
, @Service
, @Repository
, and @Configuration
.
@Component
is a general annotation that makes a class managed by Spring, allowing it to be registered as a bean.
@Service
, @Repository
, and @Controller
are more specialized versions of @Component
. They serve the same purpose but indicate the specific role of the class: @Service
for business logic, @Repository
for data access, and @Controller
for handling web requests.
@Configuration
is used for classes that contain bean definitions and application configuration.
By marking a class with one of these annotations, you ensure that it becomes a bean within the Spring context.
Once the classes are identified, the container proceeds to create instances of these annotated classes, effectively turning them into beans that the Spring context manages throughout the application's lifecycle.
As these beans are created, the container automatically handles their dependencies through Dependency Injection. This process allows classes to receive the necessary dependencies without needing to explicitly create or locate them, streamlining the development process.
Dependency Injection (DI)
First, the Spring Container adds to its context the beans (classes) marked with the annotations @Component
, @Service
, @Repository
, and @Configuration
. After this, it provides these beans to any objects that request them.
Real Life Example
Imagine you're developing an online store. You have a class OrderService
that manages orders and a class PaymentService
that handles payments. Instead of manually creating an instance of PaymentService
inside OrderService
, you can let the Spring Container create and inject PaymentService
into OrderService
.
OrderService
PaymentService
@Service public class OrderService { private final PaymentService paymentService; public OrderService(PaymentService paymentService) { this.paymentService = paymentService; } public void placeOrder() { System.out.println("Placing order..."); paymentService.processPayment(); } }
In the OrderService
class, we will have a field paymentService
that is initialized with the exact type we need (PaymentService
). Notice that we did not explicitly initialize this object, Spring did it for us!
If we had not annotated PaymentService
with @Service
, this bean would not have been added to the Spring context, and we would have encountered an error indicating that Spring could not find such a bean.
@Autowired
You can also use the @Autowired
annotation, which tells the Spring Container to inject the appropriate object into the field.
OrderService
@Service public class OrderService { private final PaymentService paymentService; @Autowired public OrderService(PaymentService paymentService) { this.paymentService = paymentService; } public void placeOrder() { System.out.println("Placing order..."); paymentService.processPayment(); } }
In Spring, starting from version 4.3, using the @Autowired
annotation is no longer required when injecting dependencies via a constructor if there is only one constructor in the class. Spring automatically determines that this constructor should be used for dependency injection.
What are the Different Types of Bean?
Imagine you have a single coffee machine at a cafе. Whenever a customer orders a coffee, the barista uses this same coffee machine to prepare each cup. The coffee machine is always the same one, not a new one for every order.
Similarly, in Spring, when you inject a bean from the Spring context, Spring provides you with the same instance of that bean every time. This is known as the singleton scope. Just like the coffee machine at the cafe, Spring ensures that you always get the same object rather than creating a new one each time.
Singleton
We can set the type using the @Scope
annotation and specify singleton
in the attributes.
SingletonService
@Service @Scope("singleton") public class SingletonService { // Class for handling business logic }
Prototype
PrototypeService
@Service @Scope("prototype") public class PrototypeService { // Class for handling business logic }
We do the same thing, but specify prototype
in the attributes. This ensures that each time we inject this bean, it will return a new object.
Summary
In this chapter on IoC (Inversion of Control) and DI (Dependency Injection), we explored how Spring manages the creation and lifecycle of beans through its container, enabling automatic dependency injection.
We discussed the default singleton
scope, where a single instance of a bean is reused, and the prototype
scope, which creates a new instance for each request, highlighting how these scopes impact object management and application design.
Obrigado pelo seu feedback!