The life cycle of the Bean

It can be divided into four stages: instantiation → attribute assignment → initialization → destruction. Some classes and interfaces provided by Spring can control the behavior of beans in each stage

The preparatory work

Entity class

public class User {
    private int uid;
    private String name;
    // Getter, setter, toString
}
Copy the code

Spring configuration file

<bean id="user" class="domain.User">
    <property name="uid" value="1"/>
    <property name="name" value="Zhang"/>
</bean>
Copy the code

InstantiationAwareBeanPostProcessorAdapter

InstantiationAwareBeanPostProcessorAdapter provides operating bean at some time in the life cycle of method, we only need to inherit it and rewrite the method, the need to take this class registered in the spring container This class is a container level, All the methods in this class applies to all the beans in the container if there are no special instructions below mentioned method, the default in InstantiationAwareBeanPostProcessorAdapter method

instantiation

<bean id="user" class="domain.User">
    <property name="uid" value="10"/>
    <property name="name" value="Zhang"/>
</bean>

<! - registered InstantiationAwareBeanPostProcessorAdapter class -- >
<bean class="MyInstantiationAwareBeanPostProcessor"/>
Copy the code

Inheritance InstantiationAwareBeanPostProcessorAdapter, rewrite postProcessBeforeInstantiation method, this method in the bean is instantiated before execution

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    @Override
    public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println(beanName + "Before instantiation ------------------");
        }
        return null; }}Copy the code

Test the

AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Copy the code

Output result:

PostProcessBeforeInstantiation method after the execution, next, spring will according to instantiate bean constructors.

If postProcessBeforeInstantiation method, return to a bean instance, the spring would not be instantiated bean, because you have been good to instantiate a bean, and as a method return values, Instead of simply returning a new bean object that is not managed by the Spring container, you need to use the method provided by Spring to create the new object. If we legitimate object of returned to the bean, the next will perform the postProcessAfterInitialization InstantiationAwareBeanPostProcessorAdapter method, this method is the initialization phase correlation method

After spring according to the constructor instantiates a bean, the next will be executed postProcessAfterInstantiation method, this method after instantiate execution, rewrite the method

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "Before instantiation ------------------");
        }
        return null;
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "After instantiation ------------------");
        }
        return true; }}Copy the code

Found in postProcessAfterInstantiation method on breakpoints, there is no attribute assignment of bean

Output result:

Attribute assignment

Instantiation phase has been completed, the next stage in attribute assignment postProcessProperties method, the method is performed before attribute assignment, the method depends upon whether perform postProcessAfterInstantiation methods return values. True: execute false: not execute

Rewrite the postProcessProperties method and change the name property to Li Si.

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "Before instantiation ------------------");
        }
        return null;
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "After instantiation ------------------");
        }
        return true;
    }
    
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println(beanName + "Before attribute assignment ------------------");
            PropertyValue pv = pvs.getPropertyValue("name");
            pv.setConvertedValue("Bill");
            return pvs;
        }
        return null; }}Copy the code

If the property in the bean is not explicitly configured in the Spring configuration file, the PVS will not record the property, and pv=null will cause a null pointer exception

<bean id="user" class="domain.User">
    <property name="uid" value="10"/>  <! PVS will not record the uid attribute if this attribute is not explicitly configured.
    <property name="name" value="Zhang"/> <! -- Display configuration -->
</bean>
Copy the code

Put a breakpoint on postProcessProperties

The output

After executing the postProcessProperties method, Spring assigns properties to the bean

Initialize the

Next, enter the initialization phase, rewrite postProcessBeforeInitialization method, this method in the bean’s initialization before the execution

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "Before instantiation ------------------");
        }
        return null;
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "After instantiation ------------------");
        }
        return true;
    }
    
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println(beanName + "Before attribute assignment ------------------");
            PropertyValue pv = pvs.getPropertyValue("name");
            pv.setConvertedValue("Bill");
            return pvs;
        }
        return null;
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "Pre-initialization");
        }
        returnbean; }}Copy the code

Output result:

If the bean implements the InitializingBean interface, the afterPropertiesSet method in the interface will be executed

public class User implements InitializingBean {
    private int uid;
    private String name;
    
    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("AfterPropertiesSet method in InitializingBean executed");
    }
    // setter, getter, toString
    
}
Copy the code

Output result:

Next, if the init-method property is configured in the bean label, init-method will be executed

<bean id="user" class="domain.User" init-method="initMethod">
    <property name="uid" value="1"/>
    <property name="name" value="Zhang"/>
</bean>
Copy the code
public class User implements InitializingBean {
    private int uid;
    private String name;
    
    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("AfterPropertiesSet method in InitializingBean executed");
    }
    
    public void initMethod(a) {
        System.out.println("Init-method in bean tag");
    }
    
    // setter, getter, toString
    
}
Copy the code

Output result:

Next spring initialized to bean, spring also provides control bean after initialization method of behavior postProcessAfterInitialization, rewrite the method

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "Before instantiation ------------------");
        }
        return null;
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "After instantiation ------------------");
        }
        return true;
    }
    
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println(beanName + "Before attribute assignment ------------------");
            PropertyValue pv = pvs.getPropertyValue("name");
            pv.setConvertedValue("Bill");
            return pvs;
        }
        return null;
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "Pre-initialization");
        }
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName) {
            System.out.println(beanName + "After initialization");
        }
        returnbean; }}Copy the code

Output result:

Mentioned earlier, if postProcessBeforeInstantiation returned to a legitimate bean, then direct execution postProecessAfterInitialization method

How to return a valid beans, here only to the User, we modify postProcessBeforeInstatiation method

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println(beanName + "Before instantiation ------------------");
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(beanClass);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.println("Before objective method :" + method+"\n");
                    Object object = methodProxy.invokeSuper(o, objects);
                    System.out.println("After target method :" + method+"\n");
                    returnobject; }});return (User) enhancer.create();
        }
        return null; }}Copy the code

Output result:

If you specify scope=”prototype” in the bean tag, return the bean to the caller, who is responsible for managing the bean’s life cycle. Spring no longer manages the life cycle of this Bean. If the scope is set to scope=”singleton”, the Bean is put into the cache pool of the Spring IoC container and the application of the Bean is returned to the caller, and Spring continues to manage the beans for subsequent life

The destruction

For beans whose Scope = “Singleton”, when the container closes, Spring will be triggered to manage the subsequent lifecycle of the Bean. If the Bean implements the DisposableBean interface, The interface’s destroy() method is called. For a Bean with scope= “Singleton,” Spring will execute the Bean’s destruction method if the Bean’s destruction method is specified through the destory-method attribute of the Bean tag

public class User implements InitializingBean.DisposableBean {
    private int uid;
    private String name;
    
    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("AfterPropertiesSet method in InitializingBean executed");
    }
    
    @Override
    public void destory(a) throws Exception {
        System.out.println("Destory method executes in DisposableBean.");
    }
    
    public void initMethod(a) {
        System.out.println("Init-method in bean tag");
    }
    
    public void destoryMethod(a) {
        System.out.println("DestoryMethod in bean tag");
    }
    
    // setter, getter, toString
    
}
Copy the code
<bean id="user" class="domain.User" init-method="initMethod" destory-method="destoryMethod">
    <property name="uid" value="1"/>
    <property name="name" value="Zhang"/>
</bean>
Copy the code

Closing the Spring container

AbstractApplicationContext context = new ClassPathXmlApplicationContext("config\spring.xml");
context.registerShutdownHook();
Copy the code

Output result:

conclusion

InitializingBean and DisposableBean are bean-level interfaces, which have the same effect as init-method and Destory-method, but spring has hacked our code for the former, It is recommended to use the latter InstantiationAwareBeanPostProcessorAdapter container level is class, it can control the bean is instantiated before, instantiated, initialize the behavior before and after initialization