When I’m learning a new framework, I like to look at things that beginners don’t like to read or don’t understand. For example, when I was learning Angular, it was obvious that ng new
would be enough to create a new project and start writing programs, but I would go deeper into the whole process of starting it. And when I was learning Spring Boot, even though Spring Initializr was really nice to use, and I could start developing applications by just selecting the packages, I wanted to understand what was going on behind the scenes of this amazing design, so I could understand the core principles of a framework.
In this article, we will explore the principles of @SpringBootApplication
, a core annotation in Spring Boot.
Create sample applications
-
Quickly building a project using the Spring Boot CLI
1
spring init --dependencies=web,lombok --groupId=com.duotify starter1
It can also be created with Spring Initializr
-
Open the project using Visual Studio Code
1
code starter1/
The current folder and file structure of the project is as follows.
|
|
Application entry points
All Java applications need an entry point to run, so you just need to find the class that contains the main()
method, which is our entry point.
|
|
There is a @SpringBootApplication
annotation on this class that declares that this is a Spring Boot application. But this @SpringBootApplication
annotation itself has several annotations applied to it, so we can see the source code by pressing F12
.
|
|
From the above code, we can find three other important annotations.
-
@SpringBootConfiguration
This
@SpringBootConfiguration
annotation is mainly used to add@Configuration
annotation to current class (DemoApplication
), you can take a look at the source code part of@SpringBootConfiguration
, he has a@Configuration
annotation applied to it.You can actually apply the
@Configuration
annotation directly toDemoApplication
, but the semantics of applying@SpringBootConfiguration
is much clearer and more readable! 👍Basically, applying the
@Configuration
annotation will allow theDemoApplication
class to be added to the Spring IoC container, and if there is a Method (Method) in the class with the@Bean
annotation, that method can be executed by Spring Boot at application startup. and the object returned by the method is added to the Spring IoC container so that other components (@Component
) can be used by constructive injection, attribute injection (@Autowired
) or method injection (@Qualifier
).This is a manual process of creating and registering Spring Bean components.
-
@EnableAutoConfiguration
The
@EnableAutoConfiguration
annotation first allows Spring Boot to automatically find all classes in the dependent package that have@Component
annotations applied to them through the@ComponentScan
definition, and automatically create and register them as Spring bean components. This process is like automatically adding@Configuration
annotations to these classes for you.Dependent packages such as
Tomcat
orSpring MVC
have a similar design, so using@EnableAutoConfiguration
can greatly simplify the amount of code. -
@ComponentScan
This
@ComponentScan
annotation is used to automatically scan the currentpackage
and allsub-package
classes annotated with the@Component
annotation and provide them to@EnableAutoConfiguration
for automatic configuration. This process is also known as Component scanning.These three tags are important because they serve different and related purposes. In general,
@EnableAutoConfiguration
and@SpringBootConfiguration
will only be applied once to the root class, and@ComponentScan
will usually only be applied to the root class. But if you have other libraries, you can decide for yourself if you want to use@ComponentScan
to find all the classes under the current class package and sub-packages that have@Component
annotated.Note: Generally speaking, fewer people apply
@Component
annotations directly to classes, instead using annotations that inherit from@Component
.@Controller
,@Service
,@Repository
,@Configuration
are all such annotations. Since@RestController
inherits from@Controller
, this is also a type of Stereotype Annotations.
Normally, you can just use the @SpringBootApplication
annotation on the root class and ignore the underlying technical details in 99% of the cases.
Demonstrate several different application scenarios
-
There is only one class for the whole application, no need for
@ComponentScan
to automatically scansub-packages
.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
package com.duotify.starter1; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @EnableAutoConfiguration public class DemoApplication { @RequestMapping("/") String home() { return "Hello World!123"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
Such examples are relatively rare and are mostly found in code examples that you will see when you first learn the Spring Boot framework.
The
@EnableAutoConfiguration
annotation here automatically configures all Spring beans, but we don’t apply@ComponentScan
, so it doesn’t automatically scan thecom.dootify.starter1
andcom.dootify.starter1.*
classes.Here is the
@RestController
annotation, whose source code looks like this, which contains the@Controller
and@ResponseBody
annotations.And the source code of the
@Controller
annotation looks like this.So in fact, he has applied
@Component
, so it will be automatically set by@EnableAutoConfiguration
annotation, so the DemoApplication class itself will be registered as a Spring bean component, so it can be executed directly as a Controller. -
There is more than one class for the whole application, we want to split the Controller class and write it separately, so we need
@ComponentScan
to automatically scan the classes insub-packages
I’ll start by changing
DemoApplication.java
to this.1 2 3 4 5 6 7 8 9 10 11 12 13
package com.duotify.starter1; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @EnableAutoConfiguration public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
Then add a
com.dootify.starter1.controllers.HomeController
class.1 2 3 4 5 6 7 8 9 10 11 12
package com.duotify.starter1.controllers; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { @RequestMapping("/") String home() { return "Hello World!"; } }
After launching the application, the
HomeController
controller will not be found because it is not registered as a Spring Bean component.We add the
@ComponentScan
annotation to theDemoApplication
class ofDemoApplication.java
.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package com.duotify.starter1; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; @EnableAutoConfiguration @ComponentScan public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
Restart the application and you can call the API without any problem!
-
We have a common object that is registered via
@Bean
and used by other components that are also registered in the Spring IoC container.Because all classes annotated with
@Component
will eventually be registered in the Spring IoC container. And all the components registered to Spring IoC container can be injected into other components. So we can add a Spring bean method to theDemoApplication
class.Once added, the
appName()
method, which has the@Bean
annotation, does not actually run automatically when the Spring Boot application starts unless you apply the@Configuration
annotation to theDemoApplication
class.The result is as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
package com.duotify.starter1; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @EnableAutoConfiguration @ComponentScan @Configuration public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean(name = "appName") public String appName() { return "Starter1"; } }
Since we have collected the
@EnableAutoConfiguration
,@ComponentScan
,@Configuration
annotations, we can now merge them directly into the@SpringBootApplication
annotation.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
package com.duotify.starter1; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean(name = "appName") public String appName() { return "Starter1"; } }
Finally, we modify the
HomeController
class and use the constructive injectionString
Spring bean to use it.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
package com.duotify.starter1.controllers; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { private String appName; public HomeController(String appName) { this.appName = appName; } @RequestMapping("/") String home() { return "Hello " + this.appName + "!"; } }
If you want to use “attribute injection”, you can also use
@Autowired
in the fields and the code will be simpler.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
package com.duotify.starter1.controllers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { @Autowired private String appName; @RequestMapping("/") String home() { return "Hello " + this.appName + "!"; } }
Testing.
Conclusion
In fact, this article has covered many basics, including
- Spring Initializr
- Spring Boot CLI
- Using the @SpringBootApplication Annotation
@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan
(Spring Component Scanning)@SpringBootConfiguration
@Configuration
- Spring Stereotype Annotations
@Component
@Controller
@RestController
@Service
@Compoment
@Repository
@Configuration
- Spring IoC Container
Because these are the core mechanisms of Spring, as long as you can understand the above concepts completely, you can understand the other parts very well! 👍
Related links
- Difference Between @ComponentScan and @EnableAutoConfiguration in Spring Boot | Baeldung
- Spring Component Scanning | Baeldung
- What is a Spring Bean? | Baeldung
- Spring Boot Change Context Path | Baeldung
Reference https://blog.miniasp.com/post/2022/09/20/How-Spring-Boot-Works