This is the most comprehensive analysis guide ever to Spring’s core processes and how they work

  • 🍃 [Spring Core] “IOC Container” will take you through the core process and operation principles of Spring without tedious source code

  • 🍃 “AOP Container” takes you through Spring’s core process and how it works without looking at the tedious source code

  • 🍃 [Spring Core topics] “MVC Container” will take you through Spring’s core processes and operating principles without tedious source code

Learn the background of Spring technology

For every Java enthusiast, whether in the field of microservices architecture technology (SpringCloud, SpringCloud-Alibaba, etc.), Or for the traditional Internet industry (SpringBoot) and software system (Spring\SpringBatch) field, master the technical principles and source code of Spring framework has a very important help and influence on the investigation of problems and future interview technology, and next, I will focus on the Spring technical framework of the core source code process points for the relevant analysis and understanding, I believe that after reading this article, Spring source code and implementation principles will have a great help and improvement.

Analyze the framework core process

Get the IOC container for the Spring framework

Main core process points of IOC container execution process:

  • Gets the singleton Bean object
  • Create a singleton Bean object
  • Create the original Bean object
  • Resolving circular dependencies
  • Populate property information
  • Initialize the Bean object
The execution flow of the getBean method
  1. The first step is to get the relevant container data object of the beanName or BeanType type, for example, to handle the name data starting with an ampersand and alias according to the associated alias.
  2. In the second step, there will be a cache pool of fetches associated by name or alias to find the object instance that fetches associated
    • If there is: The Spring framework calls the getObjectForBeanInstance method and returns the corresponding Bean instance object with two types of Bean instance types: singleton and stereotype
      • Singleton mode: If there is none in the cache, create one and put it in the cache, where the singleton object bean is intercepted and postloaded.
      • Prototype pattern: Each time a new object is created to return the related object.
    • If the current container, unable to get the corresponding to the relevant BeanName object instance, would be to want to have to find the corresponding objects parent container Bean instance, if the parent container, in direct return data object instance of the parent container, but if the parent container does not exist, would be to create Bean object instance, but before the creation, Two special Bean operation relationships are resolved.
An association between two special Bean instances
  • Parent Bean inheritance. For example, an A Bean object can inherit the attributes of the related A-parent bean and related override operations in an XML file

  • Handle the dependency operations associated with the tokely-ons, so that A dependency can be established between loading and creating beans. For example, A tokely-ons B Bean object must be loaded and created before A is created, and so on.

After that, the relevant operation control to create the bean!

Get the Spring framework’s variable container
  • SingletonObjects: Singleton level 1 cache pool – Used to store fully instantiated and initialized object beans that can be used directly if pulled from this cache pool.

  • EarlySingletonObject: singleton level 2 cache pool – a pool of objects temporarily stored for object beans that are being initialized, primarily to resolve loop dependencies.

  • SingletonFactories: Factory object mechanism used to store bean objects, mainly to create the ObjectFactory of bean objects.

The execution flow of the createBean method
  • CreateBean method entry, getSIngleton method:
    1. The associated Bean instance is retrieved from the singletonObjects collection and returned if it is not empty.
    2. If you do not get in the primary object instances of singleton buffer pool, will conduct createBeanInstance instance stage (this part, the following will detail), the corresponding BeanName will be added to the singleCurrentlyInCreation collection, This collection is primarily used to hold the associated object beans to be created, which is the first step.
    3. When through the getObject method call createBean method is to create the object instance is completed, will be will be transferred to the object instance from singleCurrentlyInCreation collection of singleObjects collection of objects in the buffer pool, mapping relationship is: BeanName – > singleObject object.
Method essentials for createBean

The analysis of the type and attribute type characteristics of the parse Bean is mainly divided into the following aspects:

  1. Resolve the type of the associated Bean object.
  2. The method modified by override annotation related to the verification and analysis process is mainly used to verify and analyze whether there are overloaded methods or overridden methods first, so that the cglib dynamic proxy does not need to perform verification, but can directly process the call.
    • There is one property: If we want to add a prototype object property to the singleton, Consider using
      ApplicationContextAware.
  3. The post-processing before bean instantiation controls the hook hook functions and related callback mechanisms.
The core method of createBean, doCreateBean
  • Call doCreateBean to create the bean instance. This method is the lowest level of createBean creation. First, it will follow the relevant BeanWrapper implementation object from the cache and clean up some temporary data.
  • If there is no relevant cache in the cache, the bean instance object is manually created, wrapped around the BeanWrapper instance class object and returned.
  • And using MergeBeanDefinitionBeanPostProcessor post processor, the object of the abstract and the inheritance of the parent bean merge processing.
  • Depending on whether the system is configured to support the option of cyclic dependencies, you can select and decide whether to use early references of the beans exposed ahead of time, mainly for handling cyclic dependencies.
  • The associated pre-exposed reference and attribute fields are then populated with attributes referenced using the popluateBean method, which also contains the concept of associated circular references.
  • Call the relevant initializeBean methods to complete the rest of the initialization tasks, including: initializeBean interface implementation, @PostConstruct annotation processing control, and init-method method property processing.
  • Register the destruction of the associated distroy-method property and the associated preDestory method control.
DoCreateBean creates the original Bean object

CreateBeanInstance (createBeanInstance, createBeanInstance)

  • Checks for class access and throws an exception mechanism if access is prohibited.
  • If the factory-method property of the object bean contains the factory factory method mechanism that is not null, the bean is created with the associated Factory method declared by the definition and the result is returned.
Objects are built by way of associated constructors

Here we will use the construct reflection to construct the instance object and return the object result of the object as follows:

  1. Create the associated BeanWrapperImpl object as a wrapper implementation class for the closed Bean instance object.
  2. If the bean definition has a factory method, it will be built directly. If the bean definition has a factory method, it will be built using a constructor.
  3. All definitions and implicit constructors of the object are analyzed and processed. MinOrArg method is used to calculate and a list of constructors sorted by the number of parameters is obtained. (This will contain the access priority and the number of parameters to sort the conditions).
  4. By default, the constructor with the least number of arguments is used. Of course, if there is a default constructor, the default constructor area is used, but if there is a non-default constructor, the constructor is built using parameter injection.
  5. Core:We have sorted the list of constructors before, and when we are done, we will filter to get the appropriate constructors to execute the construction object. What does the Spring framework do if we get a constructor with parameters?
    • We start by getting the names and types of all the relevant formal parameters in the relevant constructor.
    • When parsing parameters, this parsing method will parse some of the data already stored in the container and the associated type parameter conversion mechanism.
    • The difference between the constructor and the numeric type is calculated and the best constructor method is chosen.
    • Once we have filtered out the and constructor (finally), if we use it here to create bean object instances, we can use it directly, without further filtering.
    • We then use the initialization strategy to build the instance bean object.
    • Finally, we inject the object into our BeanWrapperImpl object model and return the object.
It can’t be built if you use the constructor or factory method

The object is then constructed in a composite fashion

  1. Build through the factory approach
  2. Build through a custom constructor
  3. Build through the default constructor

Build in a way that works with a dynamic proxy mechanism

In order to facilitate the implementation of AOP interception operation processing mechanism on the objects of the Springbean container.

Resolving circular dependencies

That is to say, pre-exposure can be avoided by factory and @lazy will not cause errors.

The IOC container article

The main method is populateBean method

The execution flow of popluteBean methods

We first get a list of properties associated with the bean injected into the class object, which we define as PVS.

  1. After the constructor has built the object, it populates it with the relevant custom attributes, but before the relevant attributes are populated, it tries to populate it with the system’s default post-processor.

Mainly through the parameter name or parameter type to parse and fill the related dependent attributes, the main means can be @autowired, @Resource, @Inject, etc.

  1. The contents of the dynamic PVS for the attributes are then populated using a post-processor.

  2. Properties are applied to the applyProperyValues method in the bean:

    • Check whether the value of the attribute has been converted. If the value of the attribute has been converted, the value is directly used without further conversion.
    • Ergodic property list, the original value of the parser attributes, in through the PropertisSourcePlaceholdConfigurer related analytical operations, and complete resolveValue analytical value.
  3. Finally, the resolveValue is converted to the corresponding type attribute.

  4. The converted value is set into the PropertyValue object, the PropertyValue object is stored into the deepCopy collection, and the deepCopy property values are injected into the bean object.

Populate by name and type
Injection by name

An injection mechanism that simply injects bean names into related non-simple types.

Injection by type
  • Mainly handle @value annotation for injection operation parsing mechanism!
  • Resolves dependency injection mechanisms for arrays, lists, maps, and so on
  • Find type data information related to the time by type
  • If the number of candidates is 0, an exception is thrown. If =1, it gets directly from the candidate list, if >1, it gets the best object among multiple candidates, otherwise an exception is thrown.
  • If the candidate is of class type, it indicates that the candidate has not been instantiated, and is instantiated via beanFactory.getBean, otherwise the object instance is returned directly.

Initialize the Bean object

Mainly after all the instantiation and processing, it will need to call the relevant initialization method, which is represented as initializeBean method for initialization in the underlying framework, and the execution sequence of the judgment logic execution process is as follows:

  1. Detect whether the bean implements an interface of type xAware, and if so, inject the associated instance property object of X into the bean, primarily by calling the invokeAwareMethods method.
  2. It then performs the pre-initialization operations, such as the BeanPostProcessor and the related afterPropertiesSetting method.
  3. Perform the relevant initialization operation invokeInitMethods method.
  4. Perform post-initialization operations, such as the post-processing operation of BeanPostProcessor.