Spring Bean lifecycle

Bean generation process

Generate BeanDefinition

1. First, obtain all. class files under the specified path through ResourcePatternResolver (this file is packaged as a Resource object in Spring source code)

2. Traverse each Resource object

3. Use MetadateReaderFactory to parse the Resource object to get the MetadataReader.

4. Use MetadateReader to filter excludeFilters and includeFilters, as well as the Conditional annotation @ Conditional (the Conditional annotation cannot understand: whether there is a @ Conditional annotation on a class. If it exists, call the Conditional match method specified in the annotation to match, filter if the matching is successful, and pass if the matching fails)

5. After the filter is passed, the ScannerGenericBeanDefinition is generated based on the MetadataReader

6. Judge whether the corresponding class is an interface or an abstract class based on the metadata reader

7. If the filter passes, it means that the bean is scanned, and the ScannerGenericBeanDefinition is added to the result set.

Merge BeanDefinition

After the BeanDefinition is obtained by scanning, the Bean object can be created according to the BeanDefinition. However, the parent class BeanDefinition is supported in spring, which is similar to the Java parent-child class, but it is completely different.

Parent child BeanDefinition uses:

<bean id ="parent" class="com.qijian.service.Parent" scope="prototype"/>
<bean id="child" class="com.qijian.service.Chid" parent="parent"/>

In this definition, child is a prototype bean. Because the parent class BeanDefinition of child is parent, it inherits the scope attribute defined on the parent. Before generating bean objects based on the child, you need to merge the BeanDefinition to get the complete BeanDefinition of the child.

Class loading

After the BeanDefinition is merged, you can create a Bean object. To create a Bean, you must instantiate the object, and the instantiation must first load the class corresponding to the current BeanDefinition. In the createBean() method of AbstractAutowireCapableBeanFactory class, you will call: class <? > resolvedClass = resolveBeanClass(mbd, beanName); To load the class.

Before instantiation

After the class corresponding to the current BeanDefinition is loaded successfully, the object can be instantiated. However, before spring instantiates the object, spring provides an extension point to allow the user to control whether to take some starting actions before instantiation of one or some beans.

The extension point is: instantiawarebeanpostprocessor. Postprocessbeforeinstance().

@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  @Override
  public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {
    if ("userService".equals(beanName)) {
      System.out.println("Before instantiation");
    }
    return null;
  }
}

The above code will lead to printing before the Bean of userService is instantiated

Note: postprocessbeforeinstance() has a return value. If it is implemented as follows:

@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  @Override
  public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {
    if ("userService".equals(beanName)) {
      System.out.println("Before instantiation");
      return new UserService();
    }
    return null;
  }
}

The userservice Bean will directly return a userservice object defined by us before instantiation. If so, it means that Spring is not needed to instantiate, and the subsequent Spring dependency injection will not be carried out. Some steps will be skipped and the step after initialization will be executed directly.

instantiation

The main function of instantiation: create an object according to BeanDefinition.

Supplier create object

First, judge whether Supplier is set in BeanDefinition. If so, call Supplier's get() to get the object. You have to directly use the BeanDefinition object to set the Supplier, for example:

AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>() {
  @Override
  public Object get() {
    return new UserService();
  }
});
context.registerBeanDefinition("userService", beanDefinition);

Note: * * * supplier is also used to create objects, but * is different from the traditional object creation syntax: new

public class MySupplier {
	private int age;
	
	MySupplier(){
		System.out.println(age);
	}
	public static void main(String[] args) {
		//Create a Supplier container and declare it as TestSupplier type. At this time, the construction method of the object will not be called, that is, the object will not be created
		Supplier<TestSupplier> sup= MySupplier::new;
		System.out.println("--------");
		//Call the get() method, and the constructor of the object will be called to get the real object
		sup.get();
		//Each get will call the constructor, that is, the objects obtained are different
		sup.get();
	}
}

Create objects using factory methods

If Supplier is not set, check whether factoryMethod, that is, factory method, is set in BeanDefinition. There are two ways to set factoryMethod:

Mode 1:

Service class:

public class UserService {
  public static UserService createUserService() {
    System.out.println("implement createUserService()");
    UserService userService = new UserService();
    return userService;
  }
  public void test() {
    System.out.println("test");
  }
}
<bean id="userService" class="com.qijian.service.UserService" factory‐method="createUserService" />

Mode 2:

Service class:

public class CommonService {
  public UserService createUserService() {
    return new UserService();
  }
}
<bean id="commonService" class="com..qijian.CommonService"/>
<bean id="userService1" factory‐bean="commonService" factory‐method="createUserService"/>

Spring finds that when the current BeanDefinition method sets the factory method, it distinguishes the two ways, and then calls the factory method to get the object. It is worth noting that the beandefinition defined by @ Bean has factoryMethod and factoryBean, which is very similar to method 2 above. The method annotated by @ Bean is factoryMethod, and the AppConfig object is factoryBean. If the method annotated by @ Bean is static, the corresponding method is mode 1.

Inferential construction method

After inferring the constructor, the constructor will be used for instantiation.

In the inference construction method logic, in addition to meeting to select the construction method and find the input parameter object, it will also judge whether there are methods with * * @ Lookup annotation * * in the corresponding class. If it exists, the method is encapsulated as a LookupOverride object and added to the BeanDefinition.

During instantiation, if it is determined that there is no LookupOverride in the current BeanDefinition, an instance object is directly reflected by the construction method. If there is a LookupOverride object, that is, there is a @ Lookup annotated method in the class, a proxy object will be generated.

Post processing of BeanDefinition

After the Bean object is instantiated, the next step is to assign values to the properties of the object. spring provides an extension point before actually assigning values to attributes. MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(), you can process the BeanDefinition at this time

@Component
public class ZhouyuMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if ("userService".equals(beanName)) {
beanDefinition.getPropertyValues().add("orderService", new OrderService());
		}
	}
}

In the Spring source code, AutowiredAnnotationBeanPostProcessor is a MergedBeanDefinitionPostProcessor. Its postProcessMergedBeanDefinition() will find the injection point and cache it in a Map of the AutowiredAnnotationBeanPostProcessor object (injectionMetadataCache).

After instantiation

After processing the BeanDefinition, Spring designs another extension point: instantiawarebeanpostprocessor. Postprocessafterinstance(),

@Component
public class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  if ("userService".equals(beanName)) {
    UserService userService = (UserService) bean;
    userService.test();
  }
  return true;
 }
}

The above code is to process the object instantiated by userService.

Automatic injection

It will process @ Autowired, @ Resource, @ Value and other annotations, which are also implemented through the * * instantiaawarebeanpostprocessor. Postprocessproperties() * * extension point

Processing properties

When processing properties, we will process @ Autowired, @ Resource, @ Value and other annotations, which are also implemented through the * * instantiawarebeanpostprocessor. Postprocessproperties() * * extension point. For example, we can even implement our own automatic injection function

@Component
public class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
  if ("userService".equals(beanName)) {
    for (Field field : bean.getClass().getFields()) {
     if (field.isAnnotationPresent(ZhouyuInject.class)) {
      field.setAccessible(true);
      try {
       field.set(bean, "123");
      } catch (IllegalAccessException e) {
      e.printStackTrace();
     }
   }
 }
}
    return pvs;
  }
}

Execute Aware

After the attribute assignment is completed, Spring will execute some callbacks, including:

  1. BeanNameAware: returns beanName to the bean object.
  2. BeanClassLoaderAware: returns the classLoader to the bean object.
  3. beanFactory aware: returns beanFactory to the object.

Before initialization

Before initialization, it is also an extension point provided by Spring: BeanPostProcessor.postProcessBeforeInitialization()

@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws	BeansException {
		if ("userService".equals(beanName)) {
    		System.out.println("Before initialization");
		}
		return bean;
	}
}

Before initialization, beans with dependency injection can be processed.

initialization

1. Check whether the current Bean object implements the InitializingBean interface. If so, call its afterpropertieset() method

2. Execute the initialization method specified in BeanDefinition

initialization

1. Check whether the current Bean object implements the InitializingBean interface. If so, call its afterpropertieset() method

2. Execute the initialization method specified in BeanDefinition

After initialization

This is the last step in the Bean creation lifecycle and an extension point provided by Spring: BeanPostProcessor.postProcessAfterInitialization()

@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
			System.out.println("After initialization");
		}
		return bean;
	}
}

In this step, the Bean can be finally processed. The AOP in Spring is implemented after initialization, and the object returned after initialization is the final Bean object.

Bean destruction process

Timing: Bean destruction occurs when the Spring container is closed

When the Spring container closes:

AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
// Container closed
context.close();

Tags: Java Spring Back-end

Posted on Thu, 11 Nov 2021 13:35:46 -0500 by Manat