In this paper, the content

  1. The full life cycle of a bean
  2. Lifecycle callback interface
  3. AwareThe interface,

The life cycle of Spring beans

Hot interview question: Can you describe the Spring lifecycle?

Four life cycles

From the source point of view, there are four simple stages: instantiation -> property assignment -> initialization -> destruction

  1. Instantiate the Instantiation
  2. Property assignment Populate
  3. Initialize the Initialization
  4. Destruction of Destruction

Instantiation and property assignment correspond to the injection of constructor and setter methods, and initialization and destruction are two phases in which users can customize extensions. Interspersed between these four steps are various spring-provided container extension points.

Look at the source code to achieve AbstractAutowireCapableBeanFactory# doCreateBean, has nothing to do with the source code has been omitted, will retain a certain source English comments.

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (instanceWrapper == null) {
            // 1 instantiation phase
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
            // 2 Attribute assignment phase
			populateBean(beanName, mbd, instanceWrapper);
            // 3 Initialization phase
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		
		return exposedObject;
	}
Copy the code

Bean destruction phase source may have a look ConfigurableApplicationContext# close (), each bean will eventually transferred to the DisposableBeanAdapter# destroy () method, which is simpler.

class DisposableBeanAdapter implements DisposableBean.Runnable.Serializable {
@Override
	public void destroy(a) {
		if (this.invokeDisposableBean) {
			try {
                // 1 Implement DisposableBean destruction
				else {
					((DisposableBean) this.bean).destroy(); }}}if (this.destroyMethod ! =null) {
            // 2 Custom destruction methods
			invokeCustomDestroyMethod(this.destroyMethod);
		}
		else if (this.destroyMethodName ! =null) {
			Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
			if(methodToInvoke ! =null) { invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke)); }}}}Copy the code

Lifecycle extension points

Spring is powerful because it is easy to extend, and there are many common life-cycle-related extension points. The extension points are divided into 2 types:

  • Enhanced extensions that work on multiple beans

    1. InstantiationAwareBeanPostProcessor ACTS on the instantiation phase before and after
    2. BeanPostProcessor is used before and after the initialization phase
    3. InstantiationAwareBeanPostProcessor role before the destruction phase
  • Enhanced extensions to individual beans

    1. Initialization phase

      Three Aware interfaces: BeanNameAware BeanClassLoaderAware BeanFactoryAware

      InitializingBean interface

      Custom initialization method

    2. Destruction of phase

      DisposableBean interfaces

      Custom destruction method

Let me draw a summary picture, just to make it clear.

Tip:

BeanNameAware BeanClassLoaderAware BeanFactoryAware is set by calling the corresponding interface method during initialization; Other Aware interfaces are as follows EnvironmentAware, EmbeddedValueResolverAware, ApplicationContextAware (ResourceLoaderAware \ ApplicationEventPublisherAware \ M EssageSourceAware) is in front of the initialization through BeanPostProcessor# postProcessBeforeInitialization () to call the corresponding interface Settings.

I’ll go deeper when I have a chance to write Spring source code later.

Bean life cycle callback

In Spring Series 2: Basic Concepts and Usage of Spring containers:

I highly recommend reading the comments on the BeanFactory source code, which are very detailed and common interview questions: Describe the Spring lifecycle? There’s a very official full explanation in the notes

To be precise, the following source code comments are full life cycle callbacks, limited to the bean’s initialization and destruction phases. The full bean life cycle is analyzed in the next section.

The complete call process during initialization is as follows:

Container management of the bean lifecycle provides a lifecycle interface that allows developers to customize bean lifecycle operations such as initialization and destruction.

The bean initializes three callbacks

Spring provides three ways to initialize a bean’s callback:

  1. InitializingBean interface

    Org. Springframework. Beans. Factory. Set up a bean InitializingBean interface beans in the container to perform all the necessary attributes after initialization. The downside of this approach is that the Spirng container is coupled to the class.

  2. The
    in XML specifies the init-method method

     <bean class="com.crab.spring.ioc.demo11.BeanOne" id="beanOne" init-method="myInit"/>
    Copy the code
  3. Use the @postconstruct annotation

Now that there are three, the question arises:

  • Using three methods at once, specifying three different methods, what is the order of execution?
  • How many times do you execute the same method, 3 times?

Directly through the case to verify.

Case 1:3 ways 3 different ways

The definition of a class

public class BeanOne implements InitializingBean {
    // 1 How to implement the interface
    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("BeanOne InitializingBean afterPropertiesSet");
    }

    // Use XML init-method to configure
    public void myInit(a) {
        System.out.println("BeanOne init-method myInit");
    }

    @PostConstruct
    public void postConstruct(a) {
        System.out.println("BeanOne PostConstruct postConstruct"); }}Copy the code

Bean information is defined as an XML configuration file

<? xml version="1.0" encoding="UTF-8"? > <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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <! -- Scans the bean under the specified package and automatically DI--> <context:annotation-config/> <beanclass="com.crab.spring.ioc.demo11.BeanOne" id="beanOne" init-method="myInit"/>
</beans>

Copy the code

Run the test

    @org.junit.Test
    public void test1(a) {
        System.out.println(Start initializing the container);
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo11/spring.xml");
        System.out.println("Container in use ----");
        BeanOne beanOne = context.getBean(BeanOne.class);
        System.out.println(beanOne);
        System.out.println("Begin destroying containers.");
        context.close();
        System.out.println("End of container destruction.");
    }
Copy the code

The test results

BeanOne PostConstruct PostConstruct BeanOne InitializingBean afterPropertiesSet BeanOne init-method myInit Containers in use -- com. Crab. Spring. The ioc. Demo11. BeanOne@f0f2775Start Destroying containers End destroying containersCopy the code

Conclusion: @postconstruct > InitializingBean > XML init-method

Case 2:3 ways to specify the same method

The class definition is as follows

public class BeanTwo implements InitializingBean {
    // 1 How to implement the interface
    // 2 Use XML init-method for configuration
    // 3 Annotation mode
    @PostConstruct
    @Override
    public void afterPropertiesSet(a) throws Exception {
        System.out.println("BeanTwo InitializingBean afterPropertiesSet"); }}Copy the code

The XML configuration file and test program are similar and not duplicated.

The result is as follows

To initialize container BeanTwo InitializingBean afterPropertiesSet containers in use -- com. Crab. Spring. The ioc. Demo11. BeanTwo @ 3 f200884 began to destroy container end the destruction of the containerCopy the code

Conclusion: Three ways to specify the same method, will only be called once, not repeatedly

Consider: a class with two @postConstruct annotations init1() and init2(). Which one does the callback initialize?

Bean’s destruction callback

Like initialization callbacks, Spring provides three ways to do bean destruction callbacks:

  1. Implement the DisposableBean interface
  2. Destroy-method is configured in XML
  3. Using the @ PreDestroy

Similar to the order and times of execution conclusion:

  • Three methods To specify three different methods, callback order: @predestroy > DisposableBean > Destroy-method is configured in XML
  • The same method is specified in three ways, and the callback is only once

Integrated case

Define the class

public class BeanThree implements DisposableBean {

    // Approach 1 to DisposableBean
    @Override
    public void destroy(a) throws Exception {
        System.out.println("BeanThree DisposableBean destroy");
    }
    // Configure destroy-method in mode 2 XML
    public void destroy2(a){
        System.out.println("BeanThree destroy-method destroy3");
    }
    // Approach 3 uses the @predestroy annotation
    @PreDestroy
    public void destroy3(a){
        System.out.println("BeanThree @PreDestroy destroy3"); }}Copy the code

Configure the destruction callback in XML

<! -- Scan beans under specified package and automatically DI-->
<context:annotation-config/>

<bean class="com.crab.spring.ioc.demo11.BeanThree" destroy-method="destroy2"/>
Copy the code

Test procedures and results

    @org.junit.Test
    public void test3(a) {
        System.out.println(Start initializing the container);
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo11/spring3.xml");
        System.out.println("Container in use ----");
        BeanThree beanOne = context.getBean(BeanThree.class);
        System.out.println(beanOne);
        System.out.println("Begin destroying containers.");
        context.close();
        System.out.println("End of container destruction.");
    }

// The results are compared with the conclusionsTo initialize container vessel in use -- com. Crab. Spring. The ioc. Demo11. BeanThree@f0f2775Begin destroying the container BeanThree@PreDestroyDestroy3 BeanThree DisposableBean destroy BeanThree destroy-method Destroy3 End destroy the containerCopy the code

Think about it: how do YOU configure the default initialization and destruction callback methods globally in an XML configuration, rather than on every bean? default-init-method default-destroy-method

AwareThe interface,

The principle of analytic

Aware is a tag superinterface, and Spring provides an extensive implementation of the Aware callback interface that lets beans fetch the specific infrastructure dependencies they need from the container.

public interface Aware {}
Copy the code

Take a look at the ApplicationContextAware interface

public interface ApplicationContextAware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
Copy the code

When the ApplicationContext to create an implementation org. Springframework. Context. The ApplicationContextAware interface object instance, A reference to the ApplicationContext is provided for the instance. Go straight to the case.

Define a class to implement ApplicationContextAware

public class BeanFour implements ApplicationContextAware {
    // The container object ApplicationContext used to get the initial class object
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
    public ApplicationContext getContext(a) {
        returncontext; }}@Configuration
@ComponentScan
public class AppConfig {}Copy the code

Test procedures and results

@org.junit.Test
public void test_aware(a) {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(AppConfig.class);
    BeanFour bean = context.getBean(BeanFour.class);
    System.out.println(bean.getContext() == context);
    context.close();
}
/ / the result
true
Copy the code

As a result, the BeanFour instance has retrieved the container object that created it.

The main purpose of using the Aware interface is to capture the underlying objects related to the container, namely dependency injection, but the downside is that it strongly couples the application classes to Spring. On the other hand, dependency injection is also possible via @AutoWired, with lower coupling.

@Component
public class BeanFour2  {
    // The container object ApplicationContext used to get the initial class object
    @Autowired
    private ApplicationContext context;

    public ApplicationContext getContext(a) {
        returncontext; }}Copy the code

AwareInterface summary

Spring provides an extensive Aware callback interface that lets beans indicate to containers that they need specific infrastructure dependencies, as shown in the following table. As a general rule, the name indicates the dependency type.

The interface name
ApplicationContextAware
ApplicationEventPublisherAware
BeanClassLoaderAware
BeanFactoryAware
BeanNameAware
LoadTimeWeaverAware
MessageSourceAware
NotificationPublisherAware
ResourceLoaderAware

conclusion

This article introduces the full lifecycle of various beans, lifecycle callback interfaces, and Aware interfaces.

This source code address: github.com/kongxubihai…

Knowledge sharing, reproduced please indicate the source. Learning has no priority, the first!