Life cycle of Spring Bean

Posted by tripc1 on Fri, 04 Mar 2022 11:38:56 +0100

Turn:

Life cycle of Spring Bean

In addition to the use phase, Spring defines the bean life cycle as four phases: instantiation, attribute filling, initialization and destruction, and provides multiple extension points for each phase to customize the bean creation process. This article introduces the life cycle of bean and its expansion points, and demonstrates the whole process through vivid illustration and an example.

Spring lifecycle

Graph LR classload -- > instance -- > instance -- > populate -- > initialize -- > initializing -- > using -- > destruction

In the figure above, each arrow has the extension points provided by Spring. Class loading is not a part of the bean life cycle. It is kept on the figure purely because the first right arrow is provided, and the use stage is not within the scope of discussion. Therefore, these two use rounded rectangles.

Types of extension points

The extension points provided by Spring can be divided into:

  • A special extension point for a single bean to perceive its own process: the interface that appears below and ends with Aware, org springframework. beans. factory. Initializingbean interface and org springframework. beans. factory. Disposablebean interfaces, which define only one function. Bean implements these interfaces and rewrites the functions in them to realize the expansion point. The Spring container will call these functions when appropriate.

  • Common extension point for initialization of all ordinary beans: located at org springframework. beans. factory. The BeanPostProcessor, InstantiationAwareBeanPostProcessor and DestructionAwareBeanPostProcessor interfaces of config package define multiple extension points. When using, you need to define a special class to implement the interface and rewrite the necessary functions. The Spring container will preferentially register these implementation classes as beans, and then initialize ordinary beans after their initialization. When each ordinary bean is registered, the Spring container will try to call all registered general extension points.

    classDiagram BeanPostProcessor <|-- InstantiationAwareBeanPostProcessor BeanPostProcessor <|-- DestructionAwareBeanPostProcessor BeanPostProcessor: +postProcessBeforeInitialization() BeanPostProcessor: +postProcessAfterInitialization() InstantiationAwareBeanPostProcessor: +postProcessBeforeInstantiation() InstantiationAwareBeanPostProcessor: +postProcessAfterInstantiation() DestructionAwareBeanPostProcessor: +postProcessBeforeDestruction()

1. Instantiation

The process of creating an instance of a bean object, including using the factory pattern to create and call constructors. Spring provides two general extension points before and after instantiation through the instantiaawarebeanpostprocessor interface. Together with the process of object instantiation, the execution sequence is as follows:

  1. postProcessBeforeInstantiation: before ordinary bean objects are instantiated, they are called.
  2. Object instantiation
  3. postProcessAfterInstantiation: after the normal bean object is instantiated, it is called.

2. Attribute filling

If there is a setter function in the object and the injected property is specified through the configuration metadata, the Spring container will inject the configured value for it in this step. After completing the attribute filling, Spring provides ten special extension points through the Aware interface, which are used to sense some external information inside the bean itself. The calling sequence is as follows (among the several Aware interfaces mentioned below, the first three are in the org.springframework.beans.factory package, 4 ~ 9 are in the org.springframework.context package, and the last one is in the org.springframework.web.context package):

  1. BeanNameAware#setBeanName
  2. BeanClassLoaderAware#setBeanClassLoader
  3. BeanFactoryAware#setBeanFactory
  4. EnvironmentAware#setEnvironment
  5. EmbeddedValueResolverAware#setEmbeddedValueResolver
  6. ResourceLoaderAware#setResourceLoader (valid only in ApplicationContext)
  7. ApplicationEventPublisherAware#setApplicationEventPublisher (valid only in ApplicationContext)
  8. MessageSourceAware#setMessageSource (valid only in ApplicationContext)
  9. ApplicationContextAware#setApplicationContext (valid only in ApplicationContext)
  10. If it is a Web application, there is also ServletContextAware#setServletContext (valid only in WebApplicationContext)

After the completion of Aware extension point, there is also a special extension point for InitializingBean#afterPropertiesSet for property verification before initialization.

3. Initialization

Initialization refers to the final preparation of the Bean before it will work. It is usually performed by the function defined by the initMethod attribute of @ Bean. Spring provides two general expansion points before and after initialization through the BeanPostProcessor interface. In addition, the execution order of the initialization function is:

  1. postProcessBeforeInitialization
  2. Custom initialization function
  3. postProcessAfterInitialization

4. Destruction

Destruction refers to the process of releasing some external resources occupied by a Bean. It is usually executed by the destruction function defined by the destroyMethod attribute of the @ Bean annotation. Spring uses the general extension points of DestructionAwareBeanPostProcessor#postProcessBeforeDestruction and the special extension points provided by DisposableBean#destroy. The execution order of the three is as follows:

  1. DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
  2. DisposableBean#destroy
  3. Custom destroy function.

Example demonstration

A simple demonstration realizes all the expansion points of the bean life cycle mentioned above, and observes the execution sequence through log printing.

Implement all the special extension points in one bean

SimpleBean class

/**
 * A simple bean instance implements the full extension point of the bean life cycle provided by Spring. The internal function implementation order is the call order of each function in the bean life cycle
 */
@Slf4j(topic = "simple Bean")
public class SimpleBean
        implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware,
        EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware,
        ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private EmptyBean emptyBean;

    static {
        //The logger has not been initialized during class loading and uses standard output
        System.out.printf("[%s] simple Bean : SimpleBean Class loading loaded%n", Thread.currentThread().getName());
    }

    public SimpleBean() {
        log.info("Constructor execution, create instance");
    }

    @Autowired
    public void setEmptyBean(EmptyBean emptyBean) {
        this.emptyBean = emptyBean;
        log.info("setter Function execution, assembly {}", this.emptyBean);
    }

    /** Used to notify the bean of its own name */
    @Override
    public void setBeanName(String name) {
        log.info("bean Name is {}", name);
    }

    /** The class loader used to notify the bean to load itself */
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        log.info("Class loader is {}", classLoader);
    }

    /** Used to notify bean awareness to create its own bean factory */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        //BeanFactory may override toString(), resulting in too much log output for easy reference
        log.info("from {}@{} establish", beanFactory.getClass(), beanFactory.hashCode());
    }

    /** Set the running environment information of the bean */
    @Override
    public void setEnvironment(Environment environment) {
        //environment.toString() will output all environment information, resulting in too much log output, which is not easy to consult
        log.info("Operational JVM The model is {}", environment.getProperty("java.vm.name"));
    }

    /** Set the embedded configuration parser, which can be used to parse the text value in the configuration file embedded in the application package */
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        //In application Editor is defined in properties Name information
        log.info("The author is {}", resolver.resolveStringValue("${editor.name}"));
    }

    /** Set the parser for resource parsing, which can be used to parse resources of any format */
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        log.info("Resource parser object:{}", resourceLoader);
    }

    /** Setting the event publisher is related to the event publishing and subscription mechanism provided by Spring */
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        log.info("Event publisher object:{}", applicationEventPublisher);
    }

    /** Set the message origin, which can be used for internationalization */
    @Override
    public void setMessageSource(MessageSource messageSource) {
        log.info("Message source object:{}", messageSource);
    }

    /** Pass in the ApplicationContext reference for the current bean. You can use the container reference to get the references of other beans */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("Application context object:{}", applicationContext.getDisplayName());
    }

    /** After all property settings and behaviors defined by Aware interface are executed, it is called by BeanFactory, where the bean can verify its own configuration and finally initialize */
    @Override
    public void afterPropertiesSet() {
        log.info("The attribute assembly is completed, the verification is correct, and the initialization is started");
    }

    /** Custom initialization method */
    public void initMethod() {
        log.info("Custom initialization method");
    }

    /** Called when the container is destroyed */
    @Override
    public void destroy() {
        log.info("The container is about to close. Destroy the bean");
    }

    /** Custom destruction method */
    public void destroyMethod() {
        log.info("Custom destruction method");
    }

}
/** An empty bean for setter injection in SimpleBean */
@Component
public class EmptyBean {
}

Customize three types of common extension points

Instantiation processor

@Slf4j(topic = "Custom instantiation processor")
@Component
public class CustomInstantiationProcessor implements InstantiationAwareBeanPostProcessor {

    public CustomInstantiationProcessor() {
        log.info("InstantiationAwareBeanPostProcessor In other bean Create before create");
    }

    /** Call before other bean instantiation */
    @Override
    public Object postProcessBeforeInstantiation(Class
  
   beanClass, String beanName) throws BeansException {
        if (beanClass.equals(SimpleBean.class)) {
            log.info("{} About to instantiate", beanName);
        }
        return null;
    }

    /** After the other bean instantiation is called */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean instanceof SimpleBean) {
            log.info("{} Instantiation complete", beanName);
        }
        return true;
    }

}

Initialize processor

@Slf4j(topic = "Custom initialization processor")
@Component
public class CustomInitializationProcessor implements BeanPostProcessor {

    public CustomInitializationProcessor() {
        log.info("BeanPostProcessor In other bean Create before create");
    }

    /** Call before other bean initialization */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof SimpleBean) {
            log.info("{} About to initialize", beanName);
        }
        return bean;
    }

    /** After the other bean initialization is completed, it is called. */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof SimpleBean) {
            log.info("{} Initialization complete", beanName);
        }
        return bean;
    }
}

Destruction processor

@Slf4j(topic = "Custom destruction processor")
@Component
public class CustomDestructionProcessor implements DestructionAwareBeanPostProcessor {

    public CustomDestructionProcessor() {
        log.info("DestructionAwareBeanPostProcessor In other bean Create before create");
    }

    /** The other bean is destroyed before it is destroyed. */
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if (bean instanceof SimpleBean) {
            log.info("{} About to be destroyed", beanName);
        }
    }

}

Entry class

@Slf4j
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    private SimpleBean bean;

    @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Autowired
    public void setBean(SimpleBean bean) {
        this.bean = bean;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        log.info("{} use", bean.toString());
    }

}

Result analysis

  1. When @ PostConstruct, @ PreDestory and @ Component defined in JSR 250 are used together to define beans, the customized initialization function will be executed before initializingbean #afterpropertieset and extension point. Refer to the source code research later.

Turn:

Life cycle of Spring Bean


--Posted from Rpc