Bean scope and life cycle

Table of Contents

Prospect introduction:

scope definition

Six scopes of Bean

Singleton scope (Singleton) VS global scope (application)

How to set bean scope?

Bean life cycle


Foreground introduction:

Assume that there are two public Beans available to User A and User B. When A modifies the public Bean, User B will obtain the modified Bean.

The case is as follows:

Public Beans:

@Component
public class Users {
    @Bean
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("Java"); // [Key point: the name is Java]
        return user;
    }
}

When user A used it, he made modification operations:

@Controller
public class BeanScopesController {
    @Autowired
    private User user1;
    public User getUser1() {
        User user = user1;
        System.out.println("Bean original Name: " + user.getName());
        user.setName("Wukong"); // [Key point: Modification operation has been carried out]
        return user;
    }
}

User B uses public beans:

@Controller
public class BeanScopesController2 {
    @Autowired
    private User user1;
    public User getUser1() {
        User user = user1;
        return user;
    }
}

Print the public beans held by user A and user B:

public class BeanScopesTest {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanScopesController beanScopesController =
                context.getBean(BeanScopesController.class);
        System.out.println("Name after modification of object A:" +
                beanScopesController.getUser1().toString());
        BeanScopesController2 beanScopesController2 =
                context.getBean(BeanScopesController2.class);
        System.out.println("Name read by object B: " +
                beanScopesController2.getUser1().toString());
    }
}

operation result:

Cause analysis:

The reason for the above problem is that Bean is in singleton state by default, that is, all users use the same object. When we learned the singleton mode before, we all knew that using singleton can It improves performance to a great extent, so the scope of Bean in Spring is also singleton mode by default.

scope definition

Limiting the possible scope of variables in a program is called a scope, or a certain area in the source code where a variable is defined is called a scope.
The scope of a Bean refers to a certain behavioral mode of the Bean in the entire Spring framework. For example, the singleton scope means that the Bean has only one copy in the entire Spring. It is globally shared, so when other After modifying this value, what another person reads is the modified value.

Six scopes of Bean

When the Spring container initializes a Bean instance, it also specifies the scope of the instance. Spring has 6 types of operating domains, the last four of which are based on Spring MVC:

  • singleton: singleton domain
  • prototype: prototype operation domain (multi-instance operation field)
  • request: Request a domain
  • session: reply domain
  • application: global application domain
  • websocket: HTTP WebSocket domain

Singleton

  • Official description: (Default) Scopes a single bean definition to a single object instance for eachSpring IoC container.
  • Description: There are only two instances of Beans under this scope in the IoC container: obtaining the Bean (that is, obtaining it through applicationContext.getBean and other methods) and assembling the Bean (that is, through @Autowired annotation) are both the same object.
  • Scenario: Beans in normal state use this scope. ?Status indicates that the property status of the Bean object does not need to be updated.
  • Note: Spring selects this domain by default

prototype

  • Official description: Scopes a single bean definition to any number of object instances
  • Description: Each request for a Bean under this scope will create a new instance: Obtaining the Bean (that is, obtaining it through methods such as applicationContext.getBean) and assembling the Bean (that is, injecting it through @Autowired) are both new object instances.
  • Scenario: Usually stateful beans use this scope

request

  • Official description: Scopes a single bean definition to the lifecycle of a single HTTP requestThat is, each HTTP request has its own instance of a bean created off the back of asingle bean definition. Only valid in the context of a web-aware SpringApplicationContext
  • Description: Each HTTP request creates a new Bean instance, similar to prototype.
  • Scenario: A shared bean for an HTTP request and response.
  • Note: Restricted to use within the Spring MVC framework.

session

  • Official description: Scopes a single bean definition to the lifecycle of an HTTP Session. Onlyvalid in the context of a web-aware Spring ApplicationContext.
  • Description: In an Http Session, define a Bean instance.
  • Scenario: Shared Bean of user session, for example: recording a user’s login information.
  • Note: Restricted to use within the Spring MVC framework.

application

  • Official description: Scopes a single bean definition to the lifecycle of a ServletContext. Onlvalid in the context of a web-aware Spring ApplicationContext.
  • Description: In an Http Servlet Context, define a Bean instance.
  • Scenario: Contextual information of Web applications, such as: recording shared information of an application.
  • Note: Restricted to use within the Spring MVC framework.

Singleton VS global scope (application)

  • singleton is the working domain of Spring Core; application is the working domain of Spring Web.
  • singleton is used as an IoC container, and application is used as a Servlet container.

How to set Bean scope?

Answer: You can set the scope of a Bean through the @Scope annotation. There are two ways to set it:

  • Directly set the specific value of the scope, such as: @Scope(“prototype”);
  • Set the SCOPE XXX variables provided by ConfigurableBeanFactory and WebApplicationContext, such as @Scope(ConfigurableBeanFactory.SCOPE PROTOTYPE).
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
public class Users {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean(name = "u1")
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("Java"); // [Key point: the name is Java]
        return user;
    }
}

Bean life cycle

The so-called life cycle refers to the entire life process of an object from birth to destruction. We call this process the life cycle of an object.
The life cycle of a Bean is divided into the following 5 parts:

  1. Instantiate a Bean (create it from scratch, allocate memory space for the Bean, and call the Bean’s constructor): Instantiation ≠ Initialization
  2. Set properties (inject properties): After creating an instance, Spring will assign values to the properties of the Bean through dependency injection (DI).
  3. Initialize Bean: execute various Aware notification methods, such as BeanNameAware, BeanFactoryAware, ApplicationContextAware connection methods; calling initialization pre-method-> will call all classes that implement the BeanPostProcessor interface postProcessBeforeInitialization method. Execute initialization method (annotation method: @PostConstruct, XML method: init-methodf method), execute initialization post method -> call all the BeanPostProcessor interfaces The postProcessAfterInitialization method of the class.
  4. Using a Bean, after initialization, the Bean can be used. At this stage, the Bean executes its business logic.
  5. Destroy Bean: Destroy the Bean instance.

It should be noted that the positions of the second and third steps cannot be exchanged because the properties of the Bean may be used during initialization.

As shown below, the Bean may call its own method during initialization. If the properties are not set, a program error will occur.

@Service
    public class UserService {
        public UserService(){
            System.out.println("Debug User Service constructor method");
        }
        public void sayHi(){
            System.out.println("User Service SayHi.");
        }
    }
    @Controller
    public class UserController {
        @Resource
        private UserService userService;
        @PostConstruct
        public void postConstruct() {
            userService.sayHi();
            System.out.println("Execute User Controller construction method");
        }
    }

Here is an example of buying a house to facilitate understanding of the Bean life cycle:

  1. Buy a house first (instantiation, from ? to have);
  2. decoration (set properties);
  3. Buying appliances, such as washing machines, refrigerators, TVs, air conditioners, etc. ([Various] initialization);
  4. ?Live(make?Bean);
  5. Sell (Bean destroyed).

The following code demonstrates the life cycle process of a Bean:

spring-config.xml is as follows: (bean is BeanComponent)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.java.demo"></content:component-scan>
    <bean id="beanComponent"
          class="com.java.demo.component.BeanComponent" init-method="myInit" scope="prototype"></bean>
</beans>

Bean (BeanComponent) is as follows:

package com.java.demo.component;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class BeanComponent implements BeanNameAware, BeanPostProcessor {
    @Override
    public void setBeanName(String s) {
        System.out.println("Notification executed BeanName -> " + s);
    }

    /**
     * Initialization method in xml mode
     */
    public void myInit() {
        System.out.println("XML mode initialization");
    }

    @PostConstruct
    public void doPostConstruct() {
        System.out.println("Annotation initialization method");
    }

    public void sayHi() {
        System.out.println("Execute sayHi()");
    }

    @PreDestroy
    public void doPreDestroy() {
        System.out.println("do PreDestroy");
    }
    
    //Initialize pre-method
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("do postProcessBeforeInitialization");
        return bean;
    }
    //Initialize post method
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("do postProcessAfterInitialization");
        return bean;
    }
}

Calling class:

package com.java.demo;

import com.java.demo.component.BeanComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanComponent component = context.getBean("beanComponent", BeanComponent.class);
        component.sayHi();
        context.close();
    }
}

The execution results are as follows:

Note: Annotations and xml are used to initialize Bean here at the same time. The annotation method has a higher priority.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 139107 people are learning the system