When there is no code, what does Spring's bean instantiation process look like?

For programmers who write Java, it Springhas become one of the most popular third-party open source frameworks. While we are fully enjoying Spring IOCthe dividends brought by containers, we should also consider how Springthis large factory will Beanproduce one by one out, this issue we take a look at the discussion Springin Beanthe instantiation process.

Here we will not analyze the source code in detail, just give what classes Spring uses when completing what work, and what are the specific responsibilities of these classes. If we want to figure out Spring Beanthe inside story and detailed information of instantiation, then we can Which source code to look at? As for the specific and detailed code information, you can check Springthe code of the relevant class.

Two stages

First of all, Springlet's declare that we will call the managed dependent objects one by one Bean, which can also be seen from the xml configuration file.
Spring IOCThe container is like a machine on an assembly line that produces products, Springand the beans created are like exquisite products produced at the end of the assembly line. Since it is a machine, it must be started first, and it Springis no exception. Therefore Bean, the whole life can be divided into two stages:

Container startup phase

Bean instantiation phase

A lot of warm-up work has been done during the startup phase of the container, which is fully prepared for the subsequent instantiation of Bean. Let’s first look at what warm-up work has been done during the startup phase of the container.

Container startup phase

1. Configure meta information

We say that the Spring IOCcontainer separates the creation of object instances from the use of object instances. We no longer rely on which objects in our business to manually create by ourselves. As long as Springwe want, Springwe will hand over the dependent objects we need by injection. However, if you don't do it, I won't do it. Someone has to do it. Now that we have handed over the task of object creation Spring, Springwe need to know some necessary information for creating an object. And these necessary information can be the Springmost complete xml configuration file supported in the past, or other forms propertiesof disk files, for example , it can also be mainstream annotations, or even direct code hard-coding. In short, the necessary information required to create an object is called configuration meta-information.

<bean id="role" class="com.wbg.springxmlbean.entity.Role">
    <!-- property元素是定义类的属性,name属性定义的是属性名称 value是值
    相当于:
    Role role=new Role();
    role.setId(1);//加入Java开发交流君样:756584822一起吹水聊天
    role.setRoleName("高级工程师");
    role.setNote("重要人员");-->
    <property name="id" value="1"/>
    <property name="roleName" value="高级工程师"/>
    <property name="note" value="重要人员"/>
</bean>

2. BeanDefination

As we all know, in the Java world, everything is an object. The annotations scattered around the program code and the configuration meta information such as xml or other files saved on the disk must always be represented in the form of an object in the memory. , Just like our living people correspond to a Personclass in the Java world , and the way we Springchoose to represent these configuration meta-information in memory is that BeanDefinationwe will not analyze BeanDefinationthe code here. If you are interested, you can see the relevant source code. Here we Just need to know that the configuration meta information BeanDefinationexists in the form after it is loaded into the memory . 【references】

3. BeanDefinationReader

Everyone must be very curious, we can understand Springthe Bean definitions in the xml configuration file, but how does Spring understand these configuration meta-information? This depends on us BeanDefinationReader.
The difference is BeanDefinationReaderlike the gourd brothers, each has its own abilities. If we want to read the xml configuration meta information, then it can be used XmlBeanDefinationReader. If we want to read the propertiesconfiguration file, then we can use PropertiesBeanDefinitionReaderload. And if we want to read the annotation configuration meta-information, then we can use AnnotatedBeanDefinitionReaderloading. We can also easily customize BeanDefinationReaderto control the loading of configuration meta-information. For example, our configuration meta-information exists outside the three realms, so we can customize From outside the heaven realm BeanDefinationReader.
In general, BeanDefinationReaderthe role is to load the configuration meta-information and convert it into the form of memory. BeanDefinationIt exists in a certain place. As for where this place is, don't worry, then look down!

4. BeanDefinationRegistry

At this point in execution, I finally spare no effort to load the configuration meta information that exists everywhere into the memory and convert it into the form of BeanDefination, so that when we need to create an object instance, we can find the corresponding one BeanDefinationand create the object. So when we need a certain object, where do we find the corresponding BeanDefination? How to find BeanDefinationthe corresponding relationship or mapping relationship of the object through the id defined by Bean ? This leads to BeanDefinationRegistryit.
After Spring BeanDefinationReadergenerates the corresponding configuration meta-information by loading it into the memory BeanDefination, it registers it BeanDefinationRegistryin it, which BeanDefinationRegistryis a BeanDefinationlarge storage basket, which is also a form of key-value pairs, which is mapped to the corresponding by the id defined by a specific Bean BeanDefination.

5. BeanFactoryPostProcessor

BeanFactoryPostProcessorIt is an extension point provided by Spring during the startup phase of the container. It is mainly responsible for BeanDefinationRegistrymodifying and replacing the registered BeanDefination to a certain extent. For example, some configuration information that may be modified in our configuration meta information is scattered everywhere, which is not flexible enough, and it is troublesome to modify the corresponding configuration. At this time, we can use placeholders to configure. For example Jdbc的DataSource, when configuring the connection, you can configure it like this:

<bean id="dataSource"  
    class="org.apache.commons.dbcp.BasicDataSource"  
    destroy-method="close">  
    <property name="maxIdle" value="${jdbc.maxIdle}"></property>  
    <property name="maxActive" value="${jdbc.maxActive}"></property>  
    <property name="maxWait" value="${jdbc.maxWait}"></property>  
    <property name="minIdle" value="${jdbc.minIdle}"></property>  
  
    <property name="driverClassName"  
        value="${jdbc.driverClassName}">  
    </property>  
    <property name="url" value="${jdbc.url}"></property>  
  
    <property name="username" value="${jdbc.username}"></property>  
    <property name="password" value="${jdbc.password}"></property>  
</bean> //加入Java开发交流君样:756584822一起吹水聊天

BeanFactoryPostProcessorThe final modification will be made to the registered BeanDefinationRegistryone BeanDefination, replacing the $ placeholder with the real data in the configuration file.
At this point, even if the entire container startup phase is completed, the final product of the container startup phase is the registered BeanDefinationRegistryBeanDefination, which is Spring为Beanthe preheating work done by the instantiation. Let us review what happened during the container startup phase in the form of a picture.

Insert picture description here

Bean instantiation phase

It needs to be pointed out that Beanthere is a time difference between the container startup phase and the instantiation phase. Spring gives this decision to our programmers (Is it a little happy in an instant!). If we choose lazy loading, then until we reach out to Spring to rely on the object instance, it will all exist BeanDefinationRegistryin BeanDefinationthe form of one, that is, Springonly when we need to rely on the object, we will start the instantiation of the corresponding object. stage. And if we do not choose the lazy loading method, after the container startup phase is completed, the Beaninstantiation phase will be started immediately , and all the configurations are instantiated Beanand saved by implicitly calling the getBean method of all dependent objects .
Next, let's talk about Beanthose things about the instantiation process~

1. Object creation strategy

By this time, Springit did, creating the object began a shooting mode using the strategy, with our previous BeanDefinationRegistryin BeanDefination,creating an object way we can use reflection, you can also use the CGlibbyte-code generation to create the object. At the same time, we can flexibly configure to tell Spring what strategy to use to create the specified dependent object. Spring中BeanThe creation of is a classic application of the strategy design pattern. At this time, there should already be an instance of the specific dependent object we want in memory, but the development of the story is not as simple as we thought.

If you don’t understand the strategy pattern, you can refer to related books or related information on the Internet. This is related to the design pattern. This article mainly focuses on the overall process of Bean instantiation, and the knowledge of design patterns is not discussed.

2. BeanWrapper-the coat of the object

SpringThe ones in each Beando not exist in their original appearance. Because the Spring IOCcontainer has to manage multiple types of objects, in order to unify the access to different types of objects, Spring puts a coat on all the created Bean instances, this coat It is BeanWrapper(about BeanWrapperthe specific content of interest to consult the relevant source code). BeanWrapperIn fact, it is a simple encapsulation of reflection-related APIs, which greatly simplifies the upper layer using reflection to complete related business logic. We need to obtain the properties of an object and call the methods of an object. Now there is no need to write complicated reflection APIs. And to deal with a bunch of troublesome exceptions, BeanWrapperyou can complete related operations directly through it, which is simply not too cool.

3. Set object properties

BeanWrapperThe object wrapped in the previous step is still a small child who needs to set attributes and dependent objects for it.

For basic types of attributes, if there is a configuration in the configuration meta-information, then the setting value in the configuration meta-information will be directly used for assignment. Even if the basic type of attribute does not have a set value, the JVMattribute can still be used thanks to the object instantiation process The default initial zero value is assigned.

For attributes of reference types, Springall the objects that have been created are put into a Mapstructure. At this time, Springit is checked whether the dependent object has been included in the management scope of the container, that is Map, whether there is already an instance of the corresponding object in it. . If there is, then directly inject, if not, then Springthe instantiation process of the object will be temporarily put down, and the dependent object will be instantiated first, and then go back to complete the instantiation process of the object. 【references】

There is a Springclassic problem in China, that is Spring, how to solve the circular dependency?

A brief mention here Springis that the cyclic dependency is solved through the three-level cache, and only the Setterinjected cyclic dependency can be solved . Please think about how to solve it? Why can only be Setterinjected? For details, please refer to related blogs, documents, and books.

We know that if we want to rely on related objects and SpringAPIs in Spring , we can implement the corresponding Awareinterfaces, and the Spring IOCcontainer will automatically inject related dependent object instances for us. Spring IOCContainers can be roughly divided into two types. BeanFactory provides all the functions envisaged by IOC thinking, and also incorporates related functional modules such as AOP. It can be said that it BeanFactoryis a basic IOC container provided by Spring. ApplicationContextBuilt on BeanFactorytop, it also provides functions such as time release in the container, unified resource loading strategy, and internationalization support. It is a more advanced IOC container provided by Spring. //Join in the Java development exchange: 756584822 Let’s blow water and chat together. Having
said so much, I actually want to express that BeanFactoryfor this step, the implementation of this step is to check the relevant Awareinterfaces first , and then go to the Spring object pool (that is, the container, also It is the Map structure) to find the relevant instance (for example, for the ApplicationContextAwareinterface, to find the ApplicationContextinstance), that is to say, we must register the relevant instance in the container in the configuration file or use annotations, BeanFactorybefore we can automatically injection. 【references】

As for ApplicationContext, because it inherits a series of related interfaces, when Aware related interfaces are detected and related dependent objects are needed, ApplicationContext完全可以将自身注入到其中,ApplicationContext 实现这一步是通过下面要讲到的东东——BeanPostProcessor`.

For example, ApplicationContextinherit from ResourceLoader和MessageSource, then when we implement ResourceLoaderAwareand MessageSourceAwarerelated interfaces, we can inject itself into the business object.

5. BeanPostProcessor pre-processing

Ugh? What processor is that just now? I believe people who have just watched these two things must be a bit dizzy. I was also at the beginning, but in fact, it is easy to distinguish. Just remember that BeanFactoryPostProcessor exists in the container startup stage and BeanPostProcessor exists in the object instantiation stage. Pay BeanFactoryPostProcessorattention to the configuration before the object is created. It is BeanPostProcessoreasy to distinguish between the modification, modification, sewing and patching, and the function enhancement and replacement after the phase concerned object has been created.

BeanPostProcessor and BeanFactoryPostProcessor are both powerful extension points of Spring in the bean production process. If you are still very unfamiliar with it, then you must know that the famous AOP (Aspect Oriented Programming) in Spring actually relies on BeanPostProcessor to enhance the Bean object function.
BeanPostProcessor pre-processing is to allow our programmers to modify and replace the Bean instance to a certain extent before the Bean instance to be produced is placed in the container. [References] The check and automatic injection of the Aware interface
mentioned earlier ApplicationContextis BeanPostProcessorachieved. In this step, Spring will check whether the relevant Aware interface is implemented in the Bean. If it is, then it Beancan inject itself into it . . AOP in Spring is implemented in this step, generating a proxy object for the native object, and then calling the method on the source object instead of using the same method call of the proxy object.

6. Custom initialization logic

After all the preparations are completed, if our Bean still has certain initialization logic, Spring will allow us to configure our initialization logic in two ways: (1) InitializingBean(2) Configure init-method parameters,
generally through configuration init-methodmethod comparison flexible.

7, BeanPostProcess post-processing

Similar to pre-processing, here is the last extension point that Spring leaves us after the Bean custom logic is also executed. We can do some extensions we want here.

8. Custom destroy logic

This step corresponds to the custom initialization logic, and there are also two ways: (1) implement the DisposableBeaninterface (2) configure destory-methodparameters.
A typical application here is dataSourcethe destory-method为数据库连接的close()` method during configuration .

9. Use

After the above steps, we can finally enjoy the convenience that Spring brings to us. At this time, we treat the Bean instances that Spring generates for us like normal objects. If you think it's not bad, give it a try!

10. Call the callback destruction interface

SpringAfter serving us, the Bean will soon die (usually when the container is closed). Don’t forget our custom destruction logic. At this time, our custom destruction logic Springwill be called by callback, and then Bean ended his glorious life like this!
Let's take a look at Beanthe execution order of the instantiation phase through a picture ? 【references】


It should be pointed out that the bridge between the container startup phase and the Bean instantiation phase is that we can choose a custom-configured lazy loading strategy. If we configure the Bean lazy loading strategy, then only when we actually use the dependent object, Spring Will begin the instantiation phase of the Bean. And if we do not enable the lazy loading of Beans, after the container startup phase, it will immediately enter the Bean instantiation phase and instantiate related Beans by implicitly calling the getBean method. 【references】

Author: Hopu
Link: https://juejin.cn/post/6929672218322731022
Source: Nuggets

The latest high-frequency interview questions collected in 2021 (all organized into documents), there are a lot of dry goods, including mysql, netty, spring, thread, spring cloud, jvm, source code, algorithm and other detailed explanations. There are also detailed learning plans and interviews. Question sorting, etc. For those who need to obtain these contents, please add Q like: 756584822

Insert picture description here

【references】