Standard answer to Spring Bean life cycle

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans.

What is a bean? In Spring, instances managed by the Spring ioc container are called beans. So what is the declaration cycle of beans? This article takes you to the standard answer of Spring bean declaration cycle.

 

life cycle

It's boring to say the answer directly. Let's make an analogy.

If you enter a restaurant now and the cook can't cook the dish you want to eat, you have to teach him how to cook it at this time! So what is the process?

Show the cookbook to the back chef -- > the back chef studies it -- > the chefs modify it according to their own experience -- > start cooking -- > put seasonings -- > put other seasonings -- > put salt -- > put other seasonings -- > out of the pot -- > eliminate it

The life cycle of spring bean s is similar to the following:

Definition -- > resolution -- > modification definition -- > instantiation -- > attribute assignment -- > initialization pre enhancement -- > initialization -- > post initialization enhancement -- > use -- > Destroy

 

Bean Definition

The first step in cooking, tell the cook how to do it!

Recipe: BeanDefinition, Bean definition. There are two most common methods, xml and java annotation.

The Bean definition is to declare how Spring creates objects. If Spring is a cook, the Bean definition is a menu.

A bean defines the following 9 attributes:

  1. Class: defines how to the class of the bean.

  2. Name: defines the name of the bean

  3. Scope: defines the scope of the bean

  4. Constructor arguments: defines the construction method used

  5. Properties: properties

  6. Autowired Mode: injection model

  7. Lazy initialization mode: lazy loading

  8. Initialization method: initialization method

  9. Destruction method: destruction method

Let's focus on several key bean definition properties

Class 

Define which class a bean instantiates into. Some readers may think that I usually write @ Service @Controller @Component and the class of bean is dead. Will I deliberately define bean as other classes?

Let's start with an interesting feature. The following code demonstrates:

Here we first define Deer, that is, Deer

/**
 * This is deer.
 */
public class Deer {

  public Deer(){
    System.out.println("Dear constructs");
  }
}

Then define the Horse class, Horse

/**
 * This is horse.
 */
public class Horse {

  public Horse(){
    System.out.println("Horse constructs");
  }

}

The following code can be ignored:

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    GenericBeanDefinition definitionClass = (GenericBeanDefinition) beanFactory.getBeanDefinition("deer");
    ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
    definitionClass.setBeanClass(Horse.class);
  }
}

Then this is our test code. The following code is to construct a spring container, register a bean of Deer class, and then register the mybeanfactoryprocessor above.

public class TestApp {

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Deer.class);
    context.register(MyBeanFactoryPostProcessor.class);
    context.refresh();

    System.out.println(context.getBean("deer").getClass());
  }
}

We expect that it should be the bean of the added deer class, and the class class of the obtained bean should be deer.

Look at the actual results. After running the program, print the log as follows:

class com.example.spring.bean.lifecycle.beanclass.Horse

It actually printed out Horse. Isn't this referring to deer as Horse?!

Think again, why can mybatis only write Mapper interface for dao operation? We know that interfaces cannot be instantiated.

Yes, mybatis extends this point by modifying the class attribute in the bean definition of mapper to change the mapper's class into a FactoryBean, so as to realize the mapper's proxy class.

This phenomenon is interesting. In fact, we mainly use beanfactoryprocessor to modify the bean definition. Even if the registered bean is Deer, we modify it to Horse. Please look back on the content of beanfactoryprocessor.

This is the class attribute of the bean.

 

 

Autowired Mode

There are four injection models, namely

No: no injection, which is also the default option. This means that if we do not mark @ Autowired and other tags on a field, spring will treat the field as a normal field and will not inject it automatically.

byName: find a bean with the same name as the attribute in the container for injection.

byType: find the bean of the class of the field in the container and inject it.

Constructor: similar to byType, but injected on the constructor.

It may be too abstract. Let's take an example to illustrate:

We first define the simplest Class, which we will add to the spring container later.

public class Blue {
}

Then we declare another class, Green, which has a Blue attribute.

public class Green {

  private Blue blue;

  public Green(){
    System.out.println("Constructs with no arg");
  }

  public Green(Blue blue){
    System.out.println("Constructs with a blue arg");
    this.blue = blue;
  }

  public Blue getBlue() {
    return blue;
  }

  public void setBlue(Blue blue) {
    this.blue = blue;
  }
}

By default, we add these two classes to the spring container. Blue will not be injected into Green's bean s because @ Autowired is not added.

public class App {

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Green.class);
    context.register(Blue.class);
// context.register(AutowiringModeChangeBeanFactoryPostProcessor.class);
    context.refresh();
    Green bean = context.getBean(Green.class);
    System.out.println(bean.getBlue());
  }

}

Run the program and print out
 

In line with our expectations.

Then we implement the beanfactoryprocessor introduced in the previous example to modify Green's bean definition and change its injection model to byType.

public class AutowiringModeChangeBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("green");
    beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
  }
}

Then we'll test it again.

public class App {

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Green.class);
    context.register(Blue.class);
    context.register(AutowiringModeChangeBeanFactoryPostProcessor.class);
    context.refresh();
    Green bean = context.getBean(Green.class);
    System.out.println(bean.getBlue());
  }

}

The output becomes

It is found that the blue field in Green's bean is not empty.

The reason why this effect can be achieved is actually what we said. We changed the injection model of Green's bean to byType. spring looks for the bean of blue in the container and injects it into the attribute. So blue in green is not empty.

 

 

Bean scan

The bean definition of spring above corresponds to what we call the recipe. Then next, the chef will understand your recipe.

This step is called scanning or parsing bean definitions.

What is parsing? Is to scan our bean definition and add it to the spring container.

Here I'll put out the answer first. Our bean definitions will eventually be put into the beanDefinitionMap of BeanFactory.

Then we'll break in and see how it's added

Check the call stack and add it to BeanDefinitionMap step by step. The same principle of xml parsing is to parse the xml configuration into bean definitions. If necessary, you can even define txt parsing to add bean definitions. Parsing does not expand tracing

BeanFactoryPostProcessor

Next, the chef can modify your recipe a little.

In the first section, when we talked about bean definition, we mentioned beanfactoryprocessor.

When the spring container starts, after loading our bean definition, come to the first extension point provided by spring! That's beanfactoryprocessor.

Beanfactoryprocessor allows us to read the bean configuration information and then modify the bean definition before spring initializes the bean.

Just implement the interface and add it to the container, and spring will execute the implemented methods and make the enhancements you need.

Beanfactoryprocessor has only one method to implement {postProcessBeanFactory. In this method, we can obtain the bean definition to be modified according to the passed beanfactory. As we did when we modified the injection model and class.

 

instantiation

Next, start cooking!

Instantiation means executing the construction method.

In the finishBeanFactoryInitialization method of refresh method, all single instance non lazy loaded beans will be created, and instantiation is one of the steps.

First, we will get the bean, create the bean if it does not exist, and solve the circular dependency. We will not expand the description here, which will not affect our topic today.

If you don't know which method the bean is instantiated in, then you will interrupt on the construction method. After all, as long as the bean is instantiated, whether it is reflection or new, it will follow the construction method.

Our code is as follows:

public class Green {

    private Blue blue;

    public Green(){
        System.out.println("Constructor with no arg invoked");
    }

    public Blue getBlue() {
        return blue;
    }

    public void setBlue(Blue blue) {
        this.blue = blue;
    }
}

Trace breakpoints:

The call stack information is as follows:

In other words, Green's structure is

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

Executed in this method.

Note that instantiation is the difference between initialization. Instantiation only calls the construction method to create the object, and does not include initialization methods such as attribute assignment.

 

 

Attribute assignment

Attribute assignment, I compare it to seasoning.

After the object is constructed in the previous step, the attribute in the object has not been assigned.

There is no doubt that the next step is the assignment operation. For example, Blue is injected into Green.

This method is under the createbeaninstance method.

After this step, green's blue is assigned successfully, which can be viewed according to the breakpoint.

 

For the specific populate steps, you can follow the source code if you are interested. I'll release the line of code to get green, and the partners can break in and have a look.

At org springframework. beans. factory. support. DefaultListableBeanFactory#

Resolve the dependency in the doResolveDependency # method, and then enter the breakpoint in the following figure:

 

It is worth noting that when we tested the injection model before, the set injection type byType or byName was also processed in populateBean. The code is as follows:

 

It doesn't matter if you don't understand. These small details will be omitted first. We know that this step is to assign attributes!

What are the next steps? Attribute assignment is finished. What else do you want to do?

 

 

initialization

Here, I classify initialization, pre enhancement, initialization and post enhancement as initialization.

Similar to the analogy of cooking, it is to put other condiments, salt and other condiments.

The user-defined initialization operation can also be extended here by implementing the BeanPostProcessor interface.

With BeanPostProcessor, custom logic can be applied to modify beans. In other words, after the bean instantiation and assignment operations are completed, we are allowed to perform some operations before and after calling the init method through this interface.

Of course, we can also define the init method! You can implement the InitializingBean interface or add the @ PostConstruct annotation to the initialization method.

BeanPostProcessor has two methods
postprocessBeforeInitialization()
postProcessAfterInitialization()

See the name and meaning, which are the methods before and after init.

The source code of the implementation is as follows:

 

This is not initialization pre enhancement (put other seasonings), initialization (put salt), initialization post enhancement (put other seasonings)!

Next, let's verify it.

First, we implement a BeanPostProcessor. We do nothing but print information.

public class MyBeanPostProcessor implements BeanPostProcessor {

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("before initialization");
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("after initialization");
    return bean;
  }
}

Then implement the InitializingBean} interface or use the @ PostConstruct annotation.

public class Green {

  private Blue blue;

  @PostConstruct
  public void init(){
    System.out.println("post construct");
  }

  public Green(){
    System.out.println("Constructs with no arg");
  }

  public Green(Blue blue){
    System.out.println("Constructs with a blue arg");
    this.blue = blue;
  }

  public Blue getBlue() {
    return blue;
  }

  public void setBlue(Blue blue) {
    this.blue = blue;
  }
}

You can check the execution time and length of the breakpoint. I only print the results here. The effect of breakpoint debugging by interested partners is better.

The results are as follows:

 

Confirmed my theory about initialization, before, init, after.

That is, execution

  1. postProcessBeforeInitialization() method of BeanPostProcessor

  2. Then execute the custom @ PostConstruct method

  3. Then execute the postProcessAfterInitialization() method

At this point, the creation of the bean is over.

 

As for other ApplicationContextAware and BeanNameAware, they have no special significance. If you are interested, just interrupt and have a look.

 

The rest is the use of bean s during the operation of the container.

 

I'm not going to talk about it. It's not the main play! You can test @ PreDestroy annotation by yourself, the same routine, and interrupt debugging!

 

Finally, let's go through the system:

  1. bean definition

  2. The bean definition is parsed by spring

  3. post process bean factory

  4. Constructs with no arg

  5. before initialization

  6. post construct

  7. after initialization

  8. pre destory

 

Finally, post the code. It's very simple. You can debug the breakpoint yourself. If you look at the console output, you will understand it better!

public class Green {

  @PostConstruct
  public void init(){
    System.out.println("post construct");
  }

  @PreDestroy
  public void destroy(){
    System.out.println("pre destory");
  }

  public Green(){
    System.out.println("Constructs with no arg");
  }
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    System.out.println("post process bean factory");
  }
}
public class MyBeanPostProcessor implements BeanPostProcessor {

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("before initialization");
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("after initialization");
    return bean;
  }
}
public class App {

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Green.class);
    context.register(MyBeanFactoryPostProcessor.class);
    context.register(MyBeanPostProcessor.class);
    context.refresh();
    context.registerShutdownHook();
  }

}

 

summary

Aiming at the topic of spring bean life cycle, this paper explains the whole process from bean definition to bean destruction. It is recommended to combine spring's official documents and code breakpoint debugging to thoroughly understand the whole life cycle and how we can extend it. I hope this document can help you a little.

 

Welcome to the technical official account: Java technology live of Kai brother

 

 

 

Keywords: Java

Added by forcer on Tue, 01 Feb 2022 04:47:55 +0200