Understand this Baidu interview question: the life cycle of Bean in Spring

Preface

This is actually an interview question. I was asked when I was interviewing Baidu. I didn't answer it at the time (because I was really good at it). Later I searched for the answer on the Internet and I was confused when I saw it. "In action", there is a general explanation of the Bean life cycle, but there is no code analysis, so I searched for information on the Internet by myself, and we must understand the life cycle of this Bean!

​ Most of the Beans on the Internet are verified in the life cycle of the interview. In fact, there is a complete Bean life cycle when consulting the JDK. This also verifies that the book is one-sided. The most fresh information is to consult the original JDK!!!

1. The complete life cycle of Bean

​ In traditional Java applications, the life cycle of a bean is very simple. Use the Java keyword new to instantiate the bean, and then the bean can be used. Once the bean is no longer used, it is automatically garbage collected by Java.

​ In contrast, the life cycle of Spring management Beans is much more complicated. It is very important to understand the life cycle of Beans correctly, because Spring's management of Beans is very extensible. The following shows the construction process of a Bean

Understand this Baidu interview question: the life cycle of Bean in Spring

As shown in the figure above, the life cycle of Bean is quite complicated. Let’s describe each step in the figure below:

  1. Spring starts, finds and loads beans that need to be managed by Spring, and instantiates the beans
  2. After the bean is instantiated, the introduction and value of the bean are injected into the attribute of the bean
  3. If the Bean implements the BeanNameAware interface, Spring will pass the Bean’s Id to the setBeanName() method
  4. If the Bean implements the BeanFactoryAware interface, Spring will call the setBeanFactory() method to pass the BeanFactory container instance
  5. If the Bean implements the ApplicationContextAware interface, Spring will call the setApplicationContext() method of the Bean, passing in the application context reference where the bean is located
  6. If the Bean implements the BeanPostProcessor interface, Spring will call their postProcessBeforeInitialization() method.
  7. If the Bean implements the InitializingBean interface, Spring will call their afterPropertiesSet() method. Similarly, if the bean uses the init-method to declare the initialization method, the method will also be called
  8. If the Bean implements the BeanPostProcessor interface, Spring will call their postProcessAfterInitialization() method.
  9. At this point, the Bean is ready to be used by the application. They will stay in the application context until the application context is destroyed.
  10. If the bean implements the DisposableBean interface, Spring will call its destroy() interface method. Similarly, if the bean uses the destroy-method declaration method, this method will also be called.

The above is the core interface and life cycle of Bean in Spring. The interview answering the above process is enough. But looking through the JavaDoc document, in addition to the above interface, there are other interfaces involved in the initialization process:

Excerpted from org.springframework.beans.factory.BeanFactory, all related interfaces are as follows, there is no need to highlight the above existing ones, and the additional related interfaces are highlighted below

Understand this Baidu interview question: the life cycle of Bean in Spring

​ Bean complete life cycle

The text is explained as follows:

------------initialization------------

  • BeanNameAware.setBeanName() sets the name of the bean in the bean factory that created this bean, and is called after the ordinary property setting, and is called before the InitializinngBean.afterPropertiesSet() method
  • BeanClassLoaderAware.setBeanClassLoader(): Called before InitializingBean.afterPropertiesSet() after the normal properties are set
  • BeanFactoryAware.setBeanFactory(): The callback provides its own bean instance factory, which is called after the ordinary property setting and before InitializingBean.afterPropertiesSet() or custom initialization method
  • EnvironmentAware.setEnvironment(): Set environment to be called when the component is in use
  • EmbeddedValueResolverAware.setEmbeddedValueResolver(): Set StringValueResolver to solve embedded value range problems
  • ResourceLoaderAware.setResourceLoader(): Called after ordinary bean objects, before afterPropertiesSet or custom init-method, and before ApplicationContextAware.
  • ApplicationEventPublisherAware.setApplicationEventPublisher(): Called after ordinary bean properties, and before the initialization call afterPropertiesSet or custom initialization method. Called before ApplicationContextAware.
  • MessageSourceAware.setMessageSource(): Called after ordinary bean properties, before initializing afterPropertiesSet or custom initialization methods, and before ApplicationContextAware.
  • ApplicationContextAware.setApplicationContext(): Called after the ordinary Bean object is generated, before calling InitializingBean.afterPropertiesSet or before the user-defined initialization method. Called after ResourceLoaderAware.setResourceLoader, ApplicationEventPublisherAware.setApplicationEventPublisher, MessageSourceAware.
  • ServletContextAware.setServletContext(): Set ServletContext at runtime, call it after normal bean initialization, call it before InitializingBean.afterPropertiesSet, call it after ApplicationContextAware  Note: it is when WebApplicationContext is running
  • BeanPostProcessor.postProcessBeforeInitialization(): This BeanPostProcessor is applied to the given new bean instance and called before any bean initialization callback methods (such as InitializingBean.afterPropertiesSet or custom initialization methods). This bean will be ready to populate the value of the property. The returned bean example may be wrapped by an ordinary object, and the default implementation returns a bean.
  • BeanPostProcessor.postProcessAfterInitialization(): This BeanPostProcessor is applied to a given new bean instance and is called after any bean initialization callback methods (such as InitializingBean.afterPropertiesSet or custom initialization methods). This bean will be ready to populate the value of the property. The returned bean example may be wrapped by ordinary objects
  • InitializingBean.afterPropertiesSet(): Called by BeanFactory after setting all bean properties (and satisfy BeanFactory and ApplicationContextAware).

------------destroy------------

When the BeanFactory is closed, the life cycle of the Bean will call the following methods:

DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()

Second, Bean's life cycle verification

In order to verify the Bean life cycle process, there are two forms: one is prepared for the interview, the other is prepared for understanding the whole process, let's look at the code below:

  • Book.class
public class Book implements BeanNameAware,BeanFactoryAware,
        ApplicationContextAware,InitializingBean,DisposableBean {

    private String bookName;
    public Book(){
        System.out.println("Book Initializing ");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Book.setBeanFactory invoke");
    }

    public void setBeanName(String name) {
        System.out.println("Book.setBeanName invoke");
    }

    public void destroy() throws Exception {
        System.out.println("Book.destory invoke");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Book.afterPropertiesSet invoke");
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("Book.setApplicationContext invoke");
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
        System.out.println("setBookName: Book name has set.");
    }

    public void myPostConstruct(){
        System.out.println("Book.myPostConstruct invoke");
    }

     // 自定义初始化方法
    @PostConstruct
    public void springPostConstruct(){
        System.out.println("@PostConstruct");
    }

    public void myPreDestory(){
        System.out.println("Book.myPreDestory invoke");
        System.out.println("---------------destroy-----------------");
    }

    // 自定义销毁方法
    @PreDestroy
    public void springPreDestory(){
        System.out.println("@PreDestory");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("------inside finalize-----");
    }
}
  • Customize MyBeanPostProcessor that implements BeanPostProcessor:
public class MyBeanPostProcessor implements BeanPostProcessor {

    // 容器加载的时候会加载一些其他的bean,会调用初始化前和初始化后方法
    // 这次只关注book(bean)的生命周期
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Book){
            System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Book){
            System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
        }
        return bean;
    }
}
  • Create a new Bean-Lifecycle.xml in the resources directory
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

  	<!-- 扫描bean -->
    <context:component-scan base-package="com.bean.lifecycle"/>

    <!-- 实现了用户自定义初始化和销毁方法 -->
    <bean id="book" class="com.bean.lifecycle.Book" init-method="myPostConstruct" destroy-method="myPreDestory">
      	<!-- 注入bean 属性名称 -->
        <property name="bookName" value="thingking in java" />
    </bean>

  	<!--引入自定义的BeanPostProcessor-->
    <bean class="com.bean.lifecycle.MyBeanPostProcessor"/>

</beans>
  • Do a test of the startup class and create a new SpringBeanLifecycleApplication
public class SpringBeanLifecycleApplication {

    public static void main(String[] args) throws InterruptedException {
        // 为面试而准备的Bean生命周期加载过程
        ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
        Book book = (Book)context.getBean("book");
        System.out.println("Book name = " + book.getBookName());
        ((ClassPathXmlApplicationContext) context).destroy();

    }

}

Start the test and the output results are as follows:

Book Initializing setBookName: Book name has set. Book.setBeanName invoke Book.setBeanFactory invoke Book.setApplicationContext invoke MyBeanPostProcessor.postProcessBeforeInitialization @PostConstruct Book.afterPropertiesSet invoke Book.myPostConstruct invoke MyBeanPostProcessor.postProcessAfterInitialization Book name = thingking in java

@PreDestory Book.destory invoke Book.myPreDestory invoke ---------------destroy-----------------

  • In order to verify the complete life cycle of the Bean, you need to create a new SubBookClass to inherit the Book class
public class SubBookClass extends Book implements BeanClassLoaderAware,
        EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,
        ApplicationEventPublisherAware,MessageSourceAware{

    private String bookSystem;

    public String getBookSystem() {
        return bookSystem;
    }

    public void setBookSystem(String bookSystem) {
        System.out.println("设置BookSystem 的属性值");
        this.bookSystem = bookSystem;
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("SubBookClass.setBeanClassLoader() 方法被调用了");
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("SubBookClass.setApplicationEventPublisher() 方法被调用了");
    }

    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        System.out.println("SubBookClass.setEmbeddedValueResolver() 方法被调用了");
    }

    public void setEnvironment(Environment environment) {
        System.out.println("SubBookClass.setEnvironment() 方法被调用了");
    }

    public void setMessageSource(MessageSource messageSource) {
        System.out.println("SubBookClass.setMessageSource() 方法被调用了");
    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("SubBookClass.setResourceLoader() 方法被调用了");
    }

}

The above-mentioned SubBookClass and Book are complementary.

  • Create a new SubBean-Lifecycle.xml and inject SubBookClass
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="bookClass" class="com.bean.lifecycle.SubBookClass" init-method="myPostConstruct" destroy-method="myPreDestory">
        <property name="bookSystem" value="Java System" />
    </bean>

    <bean class="com.bean.lifecycle.MyBeanPostProcessor"/>

</beans>
  • The complete SpringBeanLifecycleApplication is as follows:
public class SpringBeanLifecycleApplication {

    public static void main(String[] args) throws InterruptedException {
        // 为面试而准备的Bean生命周期加载过程
        ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
        Book book = (Book)context.getBean("book");
        System.out.println("Book name = " + book.getBookName());
        ((ClassPathXmlApplicationContext) context).destroy();

        // 完整的加载过程,当然了解的越多越好
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SubBean-Lifecycle.xml");
        SubBookClass subBookClass = (SubBookClass) applicationContext.getBean("bookClass");
        System.out.println("BookSystemName = " + subBookClass.getBookSystem());
        ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();
    }

}

Output the complete result:

Book Initializing setBookName: Book name has set. Book.setBeanName invoke Book.setBeanFactory invoke Book.setApplicationContext invoke MyBeanPostProcessor.postProcessBeforeInitialization @PostConstruct Book.afterPropertiesSet invoke Book.myPostConstruct invoke MyBeanPostProcessor.postProcessAfterInitialization Book name = thingking in java @PreDestory Book.destory invoke Book.myPreDestory invoke ---------------destroy-----------------

Book Initializing sets the property value of BookSystem Book.setBeanName invoke SubBookClass.setBeanClassLoader() method is called Book.setBeanFactory invoke SubBookClass.setEnvironment() method is called SubBookClass.setEmbeddedValueResolver() method is called SubBookClass.setResourceLoader() method is called The SubBookClass.setApplicationEventPublisher() method is called SubBookClass.setMessageSource() The method is called Book.setApplicationContext invoke MyBeanPostProcessor.postProcessBeforeInitialization Book.afterPropertiesSet invoke Book.myPostConstruct invoke MyBeanPostProcessor.postProcessAfterInitialization BookSystemName = Java System BookDestory invoke. --------------destroy-----------------

Guess you like

Origin blog.csdn.net/doubututou/article/details/112618661