[Spring] (4) Bean scope and life cycle


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 UserBeanclass whose function is to store objects in the Spring container through @Beanannotations , which contains a and attributes:UserUseridname

@Component
public class UserBeans {
    
    
    @Bean
    public User getUser(){
    
    
        User user = new User();
        user.setId(123);
        user.setName("张三");
        return user;
    }
}

Then create a UserController1class, @Controllerstore it in the Spring container through annotations, and use it to 属性注解get the Bean object in the Spring container. In addition, create a printUsermethod, which creates a temporary reference myUserpointing 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 @Controllerannotations to store it in the Spring container, and then use it to 属性注解get the Bean object in the Spring container. In addition, create a printUsermethod 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 mainrespectively , and then execute the methods respectively to observe the impact of modifying the Bean object.ApplicationContextUserController1UserController2

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 UserController1the data of the bean is modified, UserController2the 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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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 scopethe 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, scopethe 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 @Scopeannotations 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, @Scopethe parameter in can be the name of the scope, such as: prototype; it can also be ConfigurableBeanFactoryspecified by class. ConfigurableBeanFactoryThe source code of the class:


It can be found that ConfigurableBeanFactorythe 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 UserControllerobtained 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:

  1. 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.
  2. 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.
  3. 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.
  4. Bean initialization (initialization operation):

    • If the initialization method is configured in the Bean definition (for example, using init-methodattributes or @PostConstructannotations), the Spring container will call the initialization method after instantiation to perform some initialization logic.
  5. 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.
  6. Use beans:

    • Now that the Bean has been assembled into the required classes, it can be used directly in other classes.
  7. Bean destruction (destroy operation):

    • If the bean definition is configured with a destruction method (such as using destroy-methodattributes or @PreDestroyannotations), the Spring container will call the destruction method when the container is closed to perform some cleanup operations.

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:

  1. 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.

  2. 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.

  3. 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, ApplicationContextAwareand so on.
    • Pre-initialization method : Execute BeanPostProcessorthe pre-initialization method, eg postProcessBeforeInitialization.
    • Initialization method (XML mode and annotation mode) : If the Bean defines an initialization method ( @PostConstructannotation or implements InitializingBeanan 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 BeanPostProcessorof the interface implementation class postProcessAfterInitialization, the Spring container will call this method after the Bean is initialized.
  4. 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.

  5. 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 ( @PreDestroyannotation or implements DisposableBeanan 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.xmladd 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:

  1. Instantiate the bean:

    • The Spring container reads the configuration file or scans the annotations, finds BeanComponentthe definition of and instantiates the bean. At this point, the Bean's constructor has not been called.
  2. Set properties (Bean injection and assembly):

    • If necessary, the Spring container will inject the corresponding properties into BeanComponentthe instance.
  3. Bean initialization:

    • Perform various notifications: because BeanComponentimplements BeanNameAwarethe interface, setBeanNamethe method will be called and the output will be printed 执行了通知,Bean name -> beanComponent.
    • Pre-initialization method: If it is an XML configuration method, myInitthe method will be called and the output will be printed XML 方式初始化.
    • Initialization method (@PostConstruct annotation): doPostConstructThe method will be called and the output will be printed 注解 的初始化方法.
    • Post-initialization method: postProcessAfterInitializationThe method will be called and the output will be printed do postProcessAfterInitialization.
  4. Use beans:

    • After initialization, BeanComponentthe instance can be used by the application, such as calling sayHi()methods and printing output do sayHi().
  5. Destroy the Bean object:

    • When the container is closed or the program ends, preDestroythe method will be called and the output will be printed do PreDestroy.

Note that in the above example, BeanPostProcessorthe 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, BeanPostProcessorsome 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 getBeannew Bean object.

Guess you like

Origin blog.csdn.net/qq_61635026/article/details/132080962