Bean life cycle-initialization

Introduction

Method of controlling initialization

        We can specify methods in the bean initialization phase, there are mainly the following:

  • @PostContruct
  • Implement the InitializingBean interface (afterPropertiesSet method)
  • @Bean(initMethod = "xxx")
  • Implement the BeanPostProcessor interface (postProcessBeforeInitialization method)

The overall flow of the initialization method

AnnotationConfigApplicationContext(create container)
->refresh
   ->finishBeanFactoryInitialization
      ->preInstantiateSingletons
        ->getBean
         ->doGetBean
           ->createBean
             ->doCreateBean
                -> this.populateBean(beanName, mbd, instanceWrapper);(class attribute assignment)
                     this.initializeBean(beanName, exposedObject, mbd); (BeanPostProcessor postProcessBeforeInstantiation and postProcessAfterInstantiation execution)

Example

package com.example.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class TestInitConfig {
    @Bean(name = "myUser", initMethod = "initUser")
    Object userBean() {
        return new User();
    }

    public static class User implements InitializingBean, BeanPostProcessor
    {
        static {
            System.out.println("static");
        }

        User(){
            System.out.println("construct");
        }

        public void initUser() {
            System.out.println("initMethod");
        }

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

        @PostConstruct
        public void userPostConstruct() {
            System.out.println("PostConstruct");
        }

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeanPostProcessor==> " + "beanName:" + beanName);
            return bean;
        }
    }
}

Results of the:

static
construct
PostConstruct
InitializingBean
initMethod

@PostContruct

Description

Specify the method to be executed after calling the constructor

principle

 

InitializingBean interface

Description

        Specify the method to be called during initialization, which can be configured for a specific bean.

        This method is called after all the attributes of the Bean are initialized, but when Spring configures the bean to be lazy-initialized (lazy-init) (such as @Lazy), if the class object is not used, it will not be instantiated. The class object causes the afterPropertiesSet() method of the InitializingBean subclass to fail to execute. If you need to initialize and call the afterPropertiesSet() method when the Spring container starts, you can configure it as non-lazy loading via the annotation @Lazy(value=false) (org.springframework.context.annotation.Lazy) on the class.

principle

AbstractAutowireCapableBeanFactory completes the calling of a Bean initialization method.

InvokeInitMethods in AbstractAutowireCapableBeanFactory class


/**
 * Initialize the given bean instance, applying factory callbacks
 * as well as init methods and bean post processors.
 * <p>Called from {@link #createBean} for traditionally defined beans,
 * and from {@link #initializeBean} for existing bean instances.
 * @param beanName the bean name in the factory (for debugging purposes)
 * @param bean the new bean instance we may need to initialize
 * @param mbd the bean definition that the bean was created with
 * (can also be {@code null}, if given an existing bean instance)
 * @return the initialized bean instance (potentially wrapped)
 * @see BeanNameAware
 * @see BeanClassLoaderAware
 * @see BeanFactoryAware
 * @see #applyBeanPostProcessorsBeforeInitialization
 * @see #invokeInitMethods
 * @see #applyBeanPostProcessorsAfterInitialization
 */
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        // invokeAwareMethods方法为bean设置bean名称、类加载器、bean工厂
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //通过责任链进行初始化前的处理
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //调用初始化方法,afterPropertiesSet和初始化方法就在这个方法里
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        //通过责任链进行初始化后的处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

Track invokeInitMethods (it is in AbstractAutowireCapableBeanFactory)

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
    //判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }

        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        //直接调用afterPropertiesSet
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                },getAccessControlContext());
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }                
        else {
            //直接调用afterPropertiesSet
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        //判断是否指定了init-method方法,如果指定了init-method方法,则再调用制定的init-method
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            //进一步查看该方法的源码,可以发现init-method方法中指定的方法是通过反射实现
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

        By analyzing the source code above, we can see that init-method is executed through reflection, and afterPropertiesSet is executed directly. So the execution efficiency of afterPropertiesSet is higher than init-method.

        If a bean is defined as non-singleton, then afterPropertiesSet and init-method will be executed when each instance of the bean is created. The afterPropertiesSet and init-method of a singleton bean are only called once when the bean is instantiated for the first time. In most cases, afterPropertiesSet and init-method are applied to singleton beans.

initMethod

Description

Specify the method to be called during initialization, which can be configured for a specific bean.

Spring requires init-method to be a parameterless method. If the method specified by init-method has parameters, Spring will throw java.lang.NoSuchMethodException. The method specified by init-method can be public, protected, and private, and the method can also be final.

principle

It has been mentioned in the "InitializingBean Interface" section above.

BeanPostProcessor interface

Other URL

Bean life cycle--BeanPostProcessor application

 

 

Guess you like

Origin blog.csdn.net/feiying0canglang/article/details/113905253