1. The life cycle of the bean
1.1. Bean life cycle
In the previous post we have a quick look at what bean is, today we will go a little deeper.
The life cycle of the bean is understood that from the time the bean is created until it dies, there will be different events. The bean’s life cycle can be described by the following diagram.
It may seem long and confusing, but it sort of includes the following steps:
- IoC container creates bean by calling constructor (can inject bean dependency here)
- Call the setter methods to inject beans with setter based injection
- Other constructors are called (not much concern)
@PostConstructor
is called- Init method is called
The bean will then be ready to go. If the bean is then deprecated, it is destroyed:
- Call
@PreDestroy
- Destroy beans like normal objects
1.2. @PostConstructor
and @PreDestroy
These are two quite important events with the bean, you can hook a method into it to execute when the event occurs:
@PostConstruct
is after the bean has been initialized@PreDestroy
was before the bean was destroyed
We use the above two annotations to mark a certain method, that method will be automatically called when the bean event occurs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">class</span> <span class="token class-name">Car</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Autowired</span> <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">Engine</span> engine <span class="token punctuation">;</span> <span class="token annotation punctuation">@PostConstruct</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testRun</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> engine <span class="token punctuation">.</span> <span class="token function">run</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> engine <span class="token punctuation">.</span> <span class="token function">stop</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@PreDestroy</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">stopEngine</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> engine <span class="token punctuation">.</span> <span class="token function">stop</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
As the above example code, I attach @PostConstruct
to the testRun()
method. This method is called when the Car
bean is completely created and initialized. And before the Car
is destroyed, the same stopEngine
should be called.
In practice, the above two annotations do the following tasks:
@PostConstruct
used to perform some tasks when instantiating a bean@PreDestroy
performs tasks to clean up the bean after it is used
2. Types of beans
Rather, called scopes, they are classified based on the number of beans created. The bean consists of 5 scopes:
- Singleton (default): The IoC container only creates exactly 1 object from this bean class
- Prototype: return a separate bean object for each use.
- Request: create a bean for each request
- Session: create each bean for each session
- Global session: create each bean for each global session (this doesn’t quite understand)
In the above 5 scopes we are only interested in the first two scopes. Usually you will rarely touch the prototype bean, but I also write it here.
For the singleton bean, there is no need to mark anything, it is the default. If you want to specify a class as the prototype bean, use @Scope
as follows.
1 2 3 4 5 6 | <span class="token annotation punctuation">@Component</span> <span class="token annotation punctuation">@Scope</span> <span class="token punctuation">(</span> <span class="token string">"prototype"</span> <span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">PrototypeBean</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
To clarify the prototype bean, for example bean X is used by two other beans, A, B:
- If X is a singleton bean, then only one X object is created. A and B share X.
- If X is the prototype bean, then 2 X is created for the other 2 beans using X for A and X for B.
3. How to define a bean
There are 3 ways to define a class as a bean:
- Declared in XML file
- Use annotation on class
- Use
@Configuration
and@Bean
Depending on each specific case that used accordingly. For example in this series, I do not discuss bean configuration in depth with XML (Spring Boot was born, not to configure).
3.1. Use XML, annotations
But simple, you should also know that Spring used XML to configure beans as follows. It was quite extreme so people used a better alternative.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token prolog"><?xml version = "1.0" encoding = "UTF-8"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> beans</span> <span class="token attr-name">xmlns</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> http://www.springframework.org/schema/beans <span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xmlns:</span> xsi</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> http://www.w3.org/2001/XMLSchema-instance <span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span> schemaLocation</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Đây là bean Car --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> bean</span> <span class="token attr-name">id</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> <span class="token punctuation">"</span></span> <span class="token attr-name">class</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> Car <span class="token punctuation">"</span></span> <span class="token attr-name">init-method</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> testRun <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Cấu hình thuộc tính property cho bean --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> bean</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> beans</span> <span class="token punctuation">></span></span> |
Consequently, bean configuration based on annotations such as @Component
. Specifically, as the previous post said, just mark @Component
on top of the class, IoC will know and create the bean from that class.
1 2 3 4 5 | <span class="token annotation punctuation">@Component</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Car</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
In addition, there are other more specific annotations such as @Service
, @Repository
, @Controller
, … also include @Component
, so their effect is also to create bean.
3.3. Use @Bean
inside @Configuration
This method is used for the bean that needs to perform many complex operations to initialize, or has many beans related to each other. Therefore, instead of individually initializing each class as each bean, collect the beans to be re-initialized and put in the containing class @Configuration
.
Usually, classes marked with @Configuration
have the suffix of Config.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token annotation punctuation">@Configuration</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AppConfig</span> <span class="token punctuation">{</span> <span class="token comment">// Khởi tạo trước các logic phức tạp</span> <span class="token comment">// Có thể quy định thứ tự khởi tạo bean bằng `@Order`</span> <span class="token keyword">public</span> <span class="token class-name">AppConfig</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">Car</span> <span class="token function">carBean</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Car</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">PasswordEncoder</span> <span class="token function">passwordEncoderBean</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BCryptPasswordEncoder</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Có thể định nghĩa nhiều bean khác với @Bean</span> <span class="token punctuation">}</span> |
When Spring finds @Configuration
class, it will create bean of this class first (because @Configuration
is also @Component
). During creation, the initialization logic is also executed, to prepare it for internal @Bean
creation.
Spring Boot will then find the methods marked @Bean
inside @Configuration
to create the bean. Often these beans are short and immediately return the object, not for Spring Boot to create.
Beans are also included in the ApplicationContext as usual.
However, not all marked classes can generate beans. That must be conditionally the IoC’s component scan must find it. We will move on to the component scan in a moment.
4. Component scan
4.1. How component scan works
When the Spring Boot application starts running, it will find all the classes marked as beans in the program and create the bean. The process of finding these beans is called component scan.
Component scan will find all classes in packages of the same level or lower packages
Therefore, the class marked @SpringBootApplication
containing the main method will be the starting place. Spring Boot will look down from this package (original package) to create beans.
1 2 3 4 5 6 7 8 9 10 | src/main/java/ com/tonghoangvu/demo/ DemoApplication.java components/ Engine.java ChinaEngine.java Car.java controllers/ UserController.java |
Because the default folder structure of Spring Boot it so, so from the original package DemoApplication.java
is com.tonghoangvu.demo
, it will find:
- Classes at the same level, find
DemoApplication
class, create bean - Look down the lower packages like
com.tonghoangvu.demo.components
andcom.tonghoangvu.demo.controllers
, find more classes likeChinaEngine
,Car
,UserController
(Engine.java
is the interface).
Therefore, by default all classes declared as beans can be found.
4.2. Custom search package
In case you just want Spring Boot to find beans in a specific package, for example, just look in the components
directory, there are two ways as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token comment">// Cách 1 dùng @ComponentScan với 1 hoặc nhiều string (cần có {})</span> <span class="token annotation punctuation">@ComponentScan</span> <span class="token punctuation">(</span> <span class="token string">"com.tonghoangvu.demo.components"</span> <span class="token punctuation">)</span> <span class="token comment">// Cách 2 thêm thuộc tính @SpringBootApplication scanBasePackages</span> <span class="token annotation punctuation">@SpringBootApplication</span> <span class="token punctuation">(</span> scanBasePackages <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"com.tonghoangvu.demo.components"</span> <span class="token punctuation">,</span> <span class="token string">"com.tonghoangvu.demo.controllers"</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DemoApplication</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token class-name">String</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> args <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Today’s article is finished, and it is considered that most of the theory part of Spring Boot is gone. From the next article we will learn about more practical things in Spring Boot.
Happy New Year, remember to upvote and clip if you like it. Happy Vietnamese new year