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:
- BeanNameAware: returns beanName to the bean object.
- BeanClassLoaderAware: returns the classLoader to the bean object.
- 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();