Java Spring Boot - Spring Application Context

Andrew Cho
2 min readAug 7, 2023

So you have a bit of experience with Java?

Let’s dive into Spring and Spring Boot.

Spring is a Dependency Injection framework in Java, primarily designed to manage Web APIs. In 2023 it is a breeze to set up, but there are now a lot of abstractions and annotations that hide away a lot of the implementation.

Spring Application Context

Beans, Components, Configurations. What are they?

In Object Oriented Programming we know we can instantiate a class like this:

PaymentService paymentService = new PaymentService();

paymentService.sendPayment();

But if we are using an N-Tier design pattern, our application will have a set of services that can be managed in a cleaner way. In fact, we can say that these services will have to be instantiated and kept in memory for the lifetime of our application anyway.

Using this underlying assumption, that our Spring Boot application will be a microservice with a clearly defined (single) responsibility, then we can pass the control of our service layer instantiation to the Spring framework.

We will then rely on it for Dependency Injection.

How does this work?

All Services, Controllers, Configuration classes are meta-annotated as Components. These Components are instantiated at application startup and placed into a pool of memory called the Spring Application Context (SAC). You can test this by creating a log line in the constructor for any Component class: you will see the log at application startup.

Using Autowiring these Component classes can then be injected into each other as dependencies without using the basic OOP object instantiation in the code block above. In this way we are passing the implementation of the object instantiation and dependency injection to the framework itself. This comes in handy later for Aspect Oriented Programming (AOP) which we will discuss in another article.

Now if we have multiple Services, we can do this:

@Service
@NoArgsConstructor
public class MoneyService() {
@Autowired private PaymentService paymentService;

public sendMoney() {
paymentService.payAndrew();
}
}

This is an example of member field level Autowiring.

Since the PaymentService class is already in the Spring Application Context (assuming it has the ‘@Service’ annotation as well), we can Autowire it and connect the two Service class objects in the SAC together. No explicit object instantiation needed.

We can make this even cleaner and do this:

@Service
@RequiredArgsConstructor
public class MoneyService() {
private final PaymentService paymentService;

public sendMoney() {
paymentService.payAndrew();
}
}

This is an example of implicit level constructor Autowiring.

Why does this work?

This is functionally the same as:

@Service
public class MoneyService() {
private final PaymentService paymentService;

@Autowired
public MoneyService(PaymentService paymentService) {
this.paymentService = paymentService;
}

public sendMoney() {
paymentService.payAndrew();
}
}

This is an example of constructor level Autowiring.

When we only have one constructor, the ‘@Autowired’ annotation is implicitly added to the constructor itself, and since we can annotate the constructor as ‘@RequiredArgsConstructor’ (using Lombok) for the PaymentService class marked as final, then we get all of this in the previous code block.

Clean code.

--

--