Article directory
foreword
Bean is a core concept in the Spring framework, which refers to an object instance managed by the Spring container . When developing with Spring, we usually define various Beans to carry different functions and components of the application . However, many developers may only pay attention to the definition and usage of Bean, but ignore the scope and life cycle of Bean, both of which are crucial to the performance, stability and maintainability of an application.
In this article, I discuss in depth the scope and lifecycle of beans and explain their impact on Spring applications. I will try to explain these concepts in simple and clear language so that readers can easily understand and apply them to their own development practices.
1. The scope of the bean
Seeing the term Bean scope for the first time may make us confused, but it doesn't matter, the next simple case will tell us what is Bean scope.
1.1 Modified Bean case
Now there is a public Bean object that can be used by users A and B, but when A uses this Bean object, it quietly modifies the data of this Bean, so will it cause B users to use this Bean object when unexpected results occur?
Create a UserBean
class whose function is to store objects in the Spring container through @Bean
annotations , which contains a and attributes:User
User
id
name
@Component
public class UserBeans {
@Bean
public User getUser(){
User user = new User();
user.setId(123);
user.setName("张三");
return user;
}
}
Then create a UserController1
class, @Controller
store it in the Spring container through annotations, and use it to 属性注解
get the Bean object in the Spring container. In addition, create a printUser
method, which creates a temporary reference myUser
pointing to the Bean object, and then modifies the data of the Bean:
@Controller
public class UserController1 {
@Autowired
private User user;
public void printUser(){
System.out.println("user: " + user);
User myUser = user;
myUser.setName("李四");
System.out.println("myUser: " + myUser);
System.out.println("user: " + user);
}
}
Create another one UserController2
, also use @Controller
annotations to store it in the Spring container, and then use it to 属性注解
get the Bean object in the Spring container. In addition, create a printUser
method that only prints the obtained Bean object:
@Controller
public class UserController2 {
@Resource
private User user;
public void printUser(){
System.out.println("UserController2: user -> " + user);
}
}
The methods in the startup class obtain and main
respectively , and then execute the methods respectively to observe the impact of modifying the Bean object.ApplicationContext
UserController1
UserController2
public static void main(String[] args) {
ApplicationContext context
= new ClassPathXmlApplicationContext("spring-config.xml");
UserController1 userController1
= context.getBean("userController1", UserController1.class);
UserController2 userController2
= context.getBean("userController2", UserController2.class);
userController1.printUser();
System.out.println("=========");
userController2.printUser();
}
The result of the execution is as follows:
From the results of the operation, when UserController1
the data of the bean is modified, UserController2
the data of the obtained bean is also modified at this time, then it means that there is only one copy of a bean stored in Spring, and it is a singleton mode. Therefore, the default scope of the Bean in the Spring container is the singleton mode (singleton) .
1.2 Definition of Scope
Scope (Scope) is used in programming to describe the scope of variables or identifiers accessible in the program. In other words, it specifies in which parts variables can be referenced and used . Scope is an important concept because it helps programmers avoid naming conflicts and understand the lifecycle of variables in the code .
In the Spring framework, scope (Scope) is used to define the life cycle and visibility rules of Bean objects . 作用域决定了在不同的上下文环境中,Spring 容器如何管理和提供 Bean 对象
. For example, when defining a Bean, we can specify its scope to determine its behavior in the application.
1.3 Six Scopes of Bean
When the Spring container initializes a Bean instance, it will also specify the scope of the instance. If we do not modify the scope to be specified, Spring will specify a default scope by default. The following are six scopes in Spring, the last four of which are effective based on Spring MVC, so this article will not discuss them first.
-
Singleton scope (singleton) : This is
默认
the scope of the Spring container. During the lifetime of the application, only one instance of the bean of this type will be created, and all references to the bean will execute the same object . Which stateless, thread-safe Bean objects this scope applies to, such as utility classes, configuration classes, and so on. -
Prototype scope (prototype) : Every time a Bean object is requested, the Spring container will create a new Bean instance , so in different requests, different object instances are obtained. Prototype scope is suitable for objects that have more states and need to be created and destroyed frequently, such as some session-related beans.
-
Request scope (request) : The request scope is a commonly used scope in Web applications. It means that each HTTP request will create a new Bean instance , which is only valid during the processing of the current request. When the request ends, the bean will be destroyed. Such scopes are typically used to store and process data related to a single request.
-
Session scope (session) : Session scope is the scope based on user session in Web application. Each HTTP session (Session) corresponds to a Bean instance , which is valid during the lifetime of the entire session. This scope is suitable for objects that need to maintain state throughout the session, such as user login information.
-
Global scope (application) : Global scope means that only one Bean instance is created during the life cycle of the entire Web application . Beans in this scope are visible throughout the application and are suitable for state information that needs to be shared throughout the application.
-
HTTP WebSocket scope (websocket) : HTTP WebSocket scope is the scope based on WebSocket connection. Each WebSocket connection corresponds to a bean instance, which is valid for the entire lifetime of the WebSocket connection.
The difference between singleton scope (singleton) and global scope (application):
Both singleton scope and global scope only create a single Bean object, so what's the difference between them?
1. Define the location:
- Singleton scope is part of Spring Core and takes effect throughout the Spring IoC container. It works with any type of Spring application, not just web applications.
- The global scope is part of Spring Web and takes effect in the Servlet container. It is designed specifically for web applications and is supported through the Spring Web library.
2. Scope of action:
- Singleton scope only guarantees that there will only be one instance of each bean in the Spring IoC container. There may be different instances of different Spring IoC containers throughout the application.
- Global scope ensures that there will only be one instance of each bean throughout the entire Web application. Whether in the same servlet container or a different servlet container, there is only one instance.
3. Application scenarios:
- Singleton scope is suitable for those stateless, thread-safe beans, such as tool classes, configuration classes, etc. Since the singleton bean has only one instance in the entire application, it has certain advantages in terms of performance and resource utilization.
- The global scope is suitable for those beans that need to share state information in the entire Web application, such as global configuration objects, global caches, and so on. With global scope, we can ensure that these objects have only one instance in the entire application, and are not affected by multiple servlet containers.
4. Manage containers:
- The management of the singleton scope is the responsibility of the Spring IoC container, which is managed by the IoC container provided by Spring Core and has nothing to do with the Web application.
- The management of the global scope needs to be managed by the Servlet container provided by the Spring Web library, which is related to the life cycle of the Web application.
In summary, the singleton scope applies to the entire Spring IoC container, ensuring that each bean has only one instance in the container; while the global scope applies to the entire Web application, ensuring that each bean has only one instance in the entire application. Choosing an appropriate scope depends on specific application requirements and design considerations.
1.4 Bean scope settings
In Spring, there are two ways to set the Bean scope: XML 配置和注解配置
.
1. XML configuration
In the tags in the XML configuration file <bean>
, you can use scope
the attribute to set the scope of the Bean. For example, for a Bean with prototype scope, you can configure it like this:
<bean id="myBean" class="com.spring.demo.MyBean" scope="prototype">
<!-- Bean 的属性配置 -->
</bean>
Among them, scope
the name of the scope is specified, such as: prototype, singleton.
2. Annotation configuration
Using annotations to configure the scope of beans is more concise. In Spring, you can use @Scope
annotations to specify the scope of the Bean, such as specifying the prototype scope for the class just now UserBeans
:
@Component
public class UserBeans {
@Bean(name = {
"user1"})
// @Scope("prototype") // 原型模式
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 使用全局变量设置
public User getUser(){
User user = new User();
user.setId(123);
user.setName("张三");
return user;
}
}
At this point, @Scope
the parameter in can be the name of the scope, such as: prototype; it can also be ConfigurableBeanFactory
specified by class. ConfigurableBeanFactory
The source code of the class:
It can be found that ConfigurableBeanFactory
the class is also the encapsulation of the domain name.
When the scope is set to the prototype model, run the code that just modified the Bean content again:
At this time, it can be found that both UserController
obtained are a brand new Bean object, even if one is modified, the other will not be affected.
2. Spring execution process and Bean life cycle
2.1 Spring execution process
Spring execution flow:
-
Start the Spring container:
- When the Spring container starts, it will read the configuration file or scan the annotation to obtain the definition information of the bean.
-
Instantiate Bean (allocate memory space, from scratch):
- The Spring container instantiates the Bean object according to the configuration information or annotation definition. The instantiation process may involve the invocation of constructors and the creation of dependent objects.
-
Bean registration to the Spring container (storage operation):
- The instantiated Bean is registered in the Spring container, and the container will bring it into the management scope, and assign a unique identifier (usually the name or ID of the Bean) to each Bean.
-
Bean initialization (initialization operation):
- If the initialization method is configured in the Bean definition (for example, using
init-method
attributes or@PostConstruct
annotations), the Spring container will call the initialization method after instantiation to perform some initialization logic.
- If the initialization method is configured in the Bean definition (for example, using
-
Assemble the Bean into the required class (take operation):
- When other classes need to use a Bean, the Spring container will automatically inject the corresponding Bean into the required class according to the dependency injection configuration. In this way, other classes can directly use the Bean instance without concern for the creation and management process of the Bean object.
-
Use beans:
- Now that the Bean has been assembled into the required classes, it can be used directly in other classes.
-
Bean destruction (destroy operation):
- If the bean definition is configured with a destruction method (such as using
destroy-method
attributes or@PreDestroy
annotations), the Spring container will call the destruction method when the container is closed to perform some cleanup operations.
- If the bean definition is configured with a destruction method (such as using
It should be noted that the life cycle of the Bean is under the control of the Spring container, and developers do not need to manually manage the process of creating and destroying the Bean. This is the core idea of Spring IoC (Inversion of Control). Through dependency injection, we can focus more on the realization of business logic, without having to care about the creation and management of objects.
2.2 Bean life cycle
The life cycle of a bean refers to the whole process of a bean instance from being created to being destroyed. In the Spring container, the Bean life cycle mainly includes the following stages:
-
Instantiation : At this stage, the Spring container will create Bean instances based on configuration information and annotations. This is the process of "from scratch", that is, allocate memory space and call the constructor to create a Bean instance.
-
Set properties (Bean injection and assembly) : After instantiation, the Spring container will inject property values into Bean instances according to configuration files or annotations. This is the process of dependency injection (Dependency Injection), which sets the property value of Bean through property or construction method.
-
Bean initialization : After the attribute assignment is completed, the Spring container will perform the following steps to initialize the bean:
- Various notifications : If the Bean implements the corresponding Aware interface, Spring will notify the Bean of the corresponding state through the callback method, for example,
BeanNameAware
,BeanFactoryAware
,ApplicationContextAware
and so on. - Pre-initialization method : Execute
BeanPostProcessor
the pre-initialization method, egpostProcessBeforeInitialization
. - Initialization method (XML mode and annotation mode) : If the Bean defines an initialization method (
@PostConstruct
annotation or implementsInitializingBean
an interface), the Spring container will call this method for further initialization after setting properties. - Post-initialization method : If the Bean defines a post-initialization method, such as the method
BeanPostProcessor
of the interface implementation classpostProcessAfterInitialization
, the Spring container will call this method after the Bean is initialized.
- Various notifications : If the Bean implements the corresponding Aware interface, Spring will notify the Bean of the corresponding state through the callback method, for example,
-
Using Bean : After the initialization is complete, the Bean instance can be used by the application. It will be injected into other classes, or get and call its methods through the Spring container.
-
Destroy the Bean object : When the container is closed or the program ends, the Spring container will perform the following steps to destroy the Bean:
- Destroy pre-method: If the Bean defines a destroy-method, the Spring container will call this method before the Bean is destroyed.
- Destruction method (XML mode and annotation mode): If the Bean defines a destruction method (
@PreDestroy
annotation or implementsDisposableBean
an interface), the Spring container will call this method for cleaning when the Bean is destroyed.
2.3 Demonstration of the Bean life cycle
The following code demonstrates a complete Bean life cycle process and shows the callback methods of each stage of the Bean in Spring. Let's take a look at the execution flow of the Bean life cycle:
@Component
public class BeanComponent implements BeanNameAware, BeanPostProcessor {
@Override
public void setBeanName(String s) {
System.out.println("执行了通知,Bean name -> " + s);
}
// xml 的初始化方法
public void myInit(){
System.out.println("XML 方式初始化");
}
@PostConstruct
public void doPostConstruct(){
System.out.println("注解 的初始化方法");
}
public void sayHi(){
System.out.println("do sayHi()");
}
@PreDestroy
public void preDestroy(){
System.out.println("do PreDestroy");
}
// 前置方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("do postProcessBeforeInitialization");
return bean;
}
// 后置方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("do postProcessAfterInitialization");
return bean;
}
}
First, you need to spring-config.xml
add the following content to the configuration file:
<!-- XML 配置方式 -->
<bean id="beanComponent"
class="com.spring.demo.component.BeanComponent"
scope="prototype"
init-method="myInit" ></bean>
Simulate the life cycle of a bean:
-
Instantiate the bean:
- The Spring container reads the configuration file or scans the annotations, finds
BeanComponent
the definition of and instantiates the bean. At this point, the Bean's constructor has not been called.
- The Spring container reads the configuration file or scans the annotations, finds
-
Set properties (Bean injection and assembly):
- If necessary, the Spring container will inject the corresponding properties into
BeanComponent
the instance.
- If necessary, the Spring container will inject the corresponding properties into
-
Bean initialization:
- Perform various notifications: because
BeanComponent
implementsBeanNameAware
the interface,setBeanName
the method will be called and the output will be printed执行了通知,Bean name -> beanComponent
. - Pre-initialization method: If it is an XML configuration method,
myInit
the method will be called and the output will be printedXML 方式初始化
. - Initialization method (@PostConstruct annotation):
doPostConstruct
The method will be called and the output will be printed注解 的初始化方法
. - Post-initialization method:
postProcessAfterInitialization
The method will be called and the output will be printeddo postProcessAfterInitialization
.
- Perform various notifications: because
-
Use beans:
- After initialization,
BeanComponent
the instance can be used by the application, such as callingsayHi()
methods and printing outputdo sayHi()
.
- After initialization,
-
Destroy the Bean object:
- When the container is closed or the program ends,
preDestroy
the method will be called and the output will be printeddo PreDestroy
.
- When the container is closed or the program ends,
Note that in the above example, BeanPostProcessor
the interface is used to implement the pre and post methods. This interface provides the ability to perform additional processing on the bean before and after the bean is initialized. In practical applications, BeanPostProcessor
some specific processing logic can be customized by implementing the interface, such as AOP proxy generation.
The method to start the class main
:
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
BeanComponent beanComponent= context.getBean("beanComponent", BeanComponent.class);
beanComponent.sayHi();
}
Execution result:
It is found that two notifications are executed here, the first time is usually because the Bean instantiation will be executed when the Spring context is created; the second execution is usually because the prototype mode is used, when the execution will create a getBean
new Bean object.