First, the Bean’s life cycle

As we know, the life cycle of a bean (object) refers to the process of bean creation, initialization, use, and destruction. Only. In Spring, the bean lifecycle is managed by the Spring container. One of the core features of Spring, an excellent and powerful framework, is its extensive support. Since the Srping container manages all Spring beans, there are certainly extension points open for custom extensions. Today we’ll talk about the initialization and destruction methods of beans. Spring opens up an extension interface that allows you to customize the initialization and destruction methods of beans. That is, our custom initialization and destruction methods are automatically called by the Spring container when the bean reaches the appropriate lifecycle phase. These two extension interfaces are InitializingBean and DisposableBean.

InitializingBean Interface Description

The InitializingBean interface provides a method for bean properties to be initialized. It has only one method, afterPropertiesSet. Any class that implements this interface executes this method after the bean properties are initialized.

package org.springframework.beans.factory;

public interface InitializingBean {
    void afterPropertiesSet(a) throws Exception;
}
Copy the code

For example, the UserServiceImpl class implements the InitializingBean interface and overwrites the afterPropertiesSet method.

public class UserServiceImpl implements InitializingBean {
    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("-- afterPropertiesSet method"); }}Copy the code

Three, DisposableBean interface description

The DisposableBean interface provides the bean with a method to handle when the bean is destroyed by the container. It has only one method, destroy, which all classes that implement this interface execute when the bean is destroyed.

package org.springframework.beans.factory;

public interface DisposableBean {
    void destroy(a) throws Exception;
}
Copy the code

For example, the UserServiceImpl class implements the DisposableBean interface, and override the destroy method.

public class UserServiceImpl implements DisposableBean {
    @Override
    public void destroy(a) throws Exception {
        System.out.println("-- destroy method"); }}Copy the code

Initialize the Bean

Implementing the InitializingBean interface and overriding the afterPropertiesSet method will tightly couple your code to Spring, which is not recommended if you don’t want your code to be coupled to Spring.

Alternatively, when configuring the bean, you specify the bean’s initialization method by configuring initMethod, which is also the initialization method that needs to be performed after the bean properties are initialized.

The first is faster to cast the bean to the InitializingBean interface type and then call the afterPropertiesSet method directly, while the second is less efficient to execute the initMethod method through reflection.

AfterPropertiesSet and initMethod can exist together, but the afterPropertiesSet method is executed before the initMethod method.

So the process from creation to initialization of a bean can be summarized as follows:

  1. Create the bean through the constructor
  2. Properties into
  3. Execute the afterPropertiesSet method
  4. Execute the initMethod method

Define a UserService interface, specification problem, interface oriented programming.

public interface UserService {
    void test(a);
}
Copy the code

Define a bean class that implements the InitializingBean interface.

public class UserServiceImpl implements UserService.InitializingBean {

    private UserDao userDao;

    public UserServiceImpl(a) {
        System.out.println("-- UserServiceImpl constructor");
    }

    @Autowired
    public void setUserDao(UserDao userDao) {
        System.out.println(-- setUserDao property injection method);
        this.userDao = userDao;
    }

    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("-- afterPropertiesSet method");
    }

    public void initMethod(a) {
        System.out.println("-- initMethod method");
    }
    
    @Override
    public void test(a) {}}Copy the code

Configure the bean to generate the bean of the UserServiceImpl class, which is managed by the Spring container.

@Configuration
public class UserServiceImplConfig {
	// Specify the initialization method through the initMethod property
    @Bean(initMethod = "initMethod")
    public UserServiceImpl userServiceImpl(a) {
        return newUserServiceImpl(); }}Copy the code

Start the service and you will see the following log in the startup log, indicating that the beans were created and initialized in the specified order.

-- UserServiceImpl constructor -- setUserDao property injection method -- afterPropertiesSet method -- initMethod methodCopy the code

5. Bean destruction

Overriding the destroy method by implementing the DisposableBean interface will also tightly couple your code to Spring, which is not recommended if you don’t want to couple your code to Spring.

Alternatively, when configuring the bean, configure destroyMethod to specify the bean’s destruction method, which is also the method to execute when the bean is destroyed.

The first method is faster to cast the bean to DisposableBean interface type, and then call destroy directly, while the second method is less efficient to execute destroyMethod via reflection.

Destroy and destroyMethod can exist together, but the destroy method is executed before destroyMethod.

We modify the above UserServiceImpl class as follows to implement the interface and override the destroy method.

public class UserServiceImpl implements UserService.InitializingBean.DisposableBean {

    private UserDao userDao;

    public UserServiceImpl(a) {
        System.out.println("-- UserServiceImpl constructor");
    }

    @Autowired
    public void setUserDao(UserDao userDao) {
        System.out.println(-- setUserDao property injection method);
        this.userDao = userDao;
    }

    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("-- afterPropertiesSet method");
    }

    public void initMethod(a) {
        System.out.println("-- initMethod method");
    }

    @Override
    public void destroy(a) throws Exception {
        System.out.println("-- destroy method");
    }

    public void destroyMethod(a) {
        System.out.println("-- destroyMethod method");
    }

    @Override
    public void test(a) {}}Copy the code

Configure the bean and specify destroyMethod to generate a bean of the UserServiceImpl class to be managed by the Spring container.

@Configuration
public class UserServiceImplConfig {
	// Use the initMethod property to specify the initialization method, and use the destroyMethod property to specify the method to execute when destroyed
    @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
    public UserServiceImpl userServiceImpl(a) {
        return newUserServiceImpl(); }}Copy the code

After the service is successfully started and stopped, the following log is displayed in the background log indicating that the beans are created, initialized, and destroyed in the specified order.

-- UserServiceImpl constructor -- setUserDao property injection method -- afterPropertiesSet method -- initMethod method2021-02-19 22:42:28.926  INFO 5844 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-02-19 22:42:29.748  INFO 5844 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http)With context path '' 2021-02-19 22:42:29.782 INFO 5844 -- [main] com.nobody.Application: Started Application in 20.12seconds (JVM running for 25.131)The 22:42:43 2021-02-19. 5844-932 the INFO/extShutdownHook O.S.S.C oncurrent. ThreadPoolTaskExecutor: Shutting down ExecutorService 'applicationTaskExecutor' - destroy method - destroyMethodCopy the code

Six, source code analysis

We already know that beans that implement the InitializingBean and DisposableBean interfaces will execute these two methods at bean initialization and DisposableBean destruction, respectively. How do they do this? Let’s find out from Spring source code analysis.

For those of you who have seen the Spring source code, the afterPropertiesSet call to the InitializingBean, Actually, the secret is in the Spring loaded beans AbstractAutowireCapableBeanFactory, invokeInitMethods one method is as follows:

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    // Determine whether the bean implements the InitializingBean interface, and if so, invoke the bean's afterPropertiesSet method
    boolean isInitializingBean = bean instanceof InitializingBean;
    if (isInitializingBean && (mbd == null| |! mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }

        if(System.getSecurityManager() ! =null) {
            try {
                AccessController.doPrivileged(() -> {
                    // Call afterPropertiesSet
                    ((InitializingBean)bean).afterPropertiesSet();
                    return null;
                }, this.getAccessControlContext());
            } catch (PrivilegedActionException var6) {
                throwvar6.getException(); }}else {
            // Call afterPropertiesSet((InitializingBean)bean).afterPropertiesSet(); }}if(mbd ! =null&& bean.getClass() ! = NullBean.class) {// Get the name of initMethod
        String initMethodName = mbd.getInitMethodName();
        InitMethod is executed if the initMethod method is specified and is not an afterPropertiesSet method
        if(StringUtils.hasLength(initMethodName) && (! isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && ! mbd.isExternallyManagedInitMethod(initMethodName)) {// Call the method specified by initMethod via reflection
            this.invokeCustomInitMethod(beanName, bean, mbd); }}}Copy the code

Where is the destroy method invoked when the bean is destroyed? Will actually destroyed when the Spring container, the container of all singleton bean destroyed, first in AbstractApplicationContext destroyBeans () method is used to deal with the destruction of the bean. The source code is as follows:

protected void destroyBeans(a) {
    this.getBeanFactory().destroySingletons();
}
Copy the code
public void destroySingleton(String beanName) {
   // Remove the bean from the level 3 cache
    this.removeSingleton(beanName);
    DisposableBean disposableBean;
    synchronized(this.disposableBeans) {
        // Force to DisposableBean object if you implement the DisposableBean interface
        disposableBean = (DisposableBean)this.disposableBeans.remove(beanName);
    }
	// Execute the destroy method
    this.destroyBean(beanName, disposableBean);
}
Copy the code
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
        // omit the code

		// If the DisposableBean bean object is not empty, execute the destroy method.
        if(bean ! =null) {
            try {
                bean.destroy();
            } catch (Throwable var13) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", var13); }}}// omit the code
    }
Copy the code

Seven, use mistake area

If the bean is not managed by Spring and is created manually (new), the initialization and destruction methods we defined will not be called automatically. For example:

@GetMapping("find")
public String find(a) {
    UserService userService1 = new UserServiceImpl();
    return "ok";
}
Copy the code

Calling this interface calls only its constructor methods.

-- UserServiceImpl constructorCopy the code

Second, if the bean is not a singleton but prototype, the initialization method is called every time the creation bean is fetched from the Spring container, and the destruction method is not executed when the bean object is destroyed. Because the prototypebean is created by Spring, it is not maintained after creation.

This demo project has been uploaded to Github, if you need to download, welcome Star. Github.com/LucioChn/sp…


Pay attention to wechat public number [Java], more articles and learning materials to help you give up the path of programming!