「Spring Boot #1」 Guide to @Component and @Autowired
Introduction:
This is an introductory article about two fundamental annotations in Spring Boot: @Component
and @Autowired
. To understand this section better, it's essential to grasp the following two concepts:
Installation:
You can install Spring Boot library packages in Maven by adding the spring-boot-starter-parent
as the parent of the entire project:
<parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>3.2.1</version> <relativepath> <!--lookup parent from repository--> </relativepath> </parent>
And to add libraries for web programming or server-side development, we add:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.blogspot.amztopfind</groupId>
<artifactId>spring-boot-tutorial</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>spring-boot-tutorial</name>
<description>Everything about Spring Boot</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Folder Structure:
How to run a Spring Boot application.
In traditional Java, when running an entire project, we have to define a main()
function and set it to execute first.
Similarly, in Spring Boot, we need to specify where it should initiate for the first run to set up everything.
This is accomplished by adding the @SpringBootApplication
annotation to the main class and calling SpringApplication.run(App.class, args);
to run the project.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
Reading about Dependency Injection (DI) and IoC, you'll understand that one of the primary tasks of Spring is to create a Container to hold Dependencies for us.
SpringApplication.run(App.class, args)
is precisely the command to create this container. It then scans all dependencies in your project and puts them inside.
Spring names this container as ApplicationContext
and labels the dependencies inside as Beans.
@SpringBootApplication public class App { public static void main(String[] args) { // "ApplicationContext" contains all dependencies within the project. ApplicationContext context = SpringApplication.run(App.class, args); } }
So, how does Spring know which one is a dependency? That's where the concept of @Component
comes in.
@Component
is an Annotation marked on Classes to help Spring recognize that it is a Bean.
Example:
We have an interface called Outfit
.
public interface Outfit { public void wear(); }
Implement it with the class Bikini
.
/* Mark the class with @Component This class will be understood by Spring Boot as a Bean (or dependency) And will be managed by Spring Boot */ @Component public class Bikini implements Outfit { @Override public void wear() { System.out.println("Wear bikini"); } }
Run the program and observe the result:
@SpringBootApplication public class App { public static void main(String[] args) { // The ApplicationContext is the container that holds all the Beans. ApplicationContext context = SpringApplication.run(App.class, args); // After running, the context will contain Beans marked with @Component. // Retrieve a Bean by Outfit outfit = context.getBean(Outfit.class); // Print to see what it is System.out.println("Instance: " + outfit); // Use the wear() method outfit.wear(); } }
Output:
- [1] Instance: com.blogspot.amztopfind.helloword.Bikini@6951842
- [2] Wear bikini.
- You will see that the
Outfit
now is indeed aBikini
. The class has been marked as@Component
. When Spring Boot runs, it scans all classes at the same level or in lower packages compared to the
App
class you provide to Spring (We can configure this search, which will be discussed later). During this scanning process, when it encounters a class marked with@Component
, it creates an instance and places it into theApplicationContext
for management.The running process will be as follows:
@Autowired:
Now, let's create a
Girl
class with a property namedOutfit
.I also mark
Girl
as a@Component
. This means Spring Boot needs to create an instance ofGirl
for management.
@Component public class Girl { @Autowired Outfit outfit; public Girl(Outfit outfit) { this.outfit = outfit; } // GET // SET }
I mark the Outfit
property of Girl
with the @Autowired
Annotation. This tells Spring Boot to automatically inject an instance of Outfit
into this property when initializing Girl
.
Now, try running the program.
@SpringBootApplication public class App { public static void main(String[] args) { // The ApplicationContext is the container that holds all the Beans. ApplicationContext context = SpringApplication.run(App.class, args); // After running, the context will contain Beans marked with @Component. // Retrieving a Bean Outfit outfit = context.getBean(Outfit.class); // Print to see what it is System.out.println("Output Instance: " + outfit); // Using the wear() method outfit.wear(); // Retrieving another Bean Girl girl = context.getBean(Girl.class); // Printing the Girl bean instance System.out.println("Girl Instance: " + girl); // Printing the Outfit associated with the Girl System.out.println("Girl Outfit: " + girl.outfit); // Using the wear() method of the outfit associated with the Girl girl.outfit.wear(); } }
Output:
- [1] Output Instance: com.blogspot.amztopfind.helloword.Bikini@6951842
- [2] Wear bikini.
- [3] Girl Instance: com.blogspot.amztopfind.helloword.Girl@2ced5f67
- [4] Girl Outfit: com.blogspot.amztopfind.helloword.Bikini@6951842
- [5] Wear bikini.
- [6] true
Spring Boot automatically creates a
Girl
, and during the creation process, it injectsOutfit
as a property.Singleton:
An important point is that all Beans managed within
ApplicationContext
are singletons. You may have noticed this from the outputs above.- [1] Output Instance: com.blogspot.amztopfind.helloword.Bikini@6951842
- [4] Girl Outfit: com.blogspot.amztopfind.helloword.Bikini@6951842
The
Outfit
in the two objects is the same.All Beans managed within
ApplicationContext
are created only once, and when a Class requires@Autowired
, it takes the available object fromApplicationContext
to inject.In case you want a completely new instance every time you use it, then mark that
@Component
with@Scope("prototype")
.
@Component @Scope("prototype") public class Bikini implements Outfit { @Override public void wear() { System.out.println("Wear bikini"); } }
Conclusion:
By now, you have gained an understanding of the two most fundamental concepts in Spring Boot, which are also its core foundation. Understanding how @Component
and @Autowired
operate means you've already covered half the journey.