Preface
Let’s talk about the instantiation process of beans. In this article, the situation of bean circular dependence is not analyzed for the time being, because it is more complicated and will be placed in a separate article later for analysis.
Preparation
Look at the following sentenceAnnotationConfigApplicationContext
Classicrefresh
The method starts with the following statement:
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
As can be seen from the official comments, this is used to complete the instantiation process of all non-lazy loading beans.
Let's write a simple bean for testing,Dao
It is also a bean that is left to spring to manage. spring will scan to this class and add it tobeanDefinitionMap
andBeanDefinitionNames
middle:
@Component public class MyService { @Autowired private Dao dao; public void query(){ ("executing query method"); (); } }
Take a lookfinishBeanFactoryInitialization
Code in:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { //If there is a conversionService in bdMap, initialization will be performed //This bean can be used to provide data conversion function if ((CONVERSION_SERVICE_BEAN_NAME) && (CONVERSION_SERVICE_BEAN_NAME, )) { ( (CONVERSION_SERVICE_BEAN_NAME, )); } if (!()) { (strVal -> getEnvironment().resolvePlaceholders(strVal)); } //Initialize bean with type LoadTimeWeaverAware // Can be used in AspectJ static weaving process String[] weaverAwareNames = (, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } //Destroy the temporary ClassLoader generated in prepareBeanFactory() before (null); //Frozen the modification to BeanDefinition here //Prevent spring from modifying BeanDefinition during initialization (); (); }
In this method, the first step is to do some preparation work until the endbeanFactory
ofpreInstantiateSingletons
The method begins to prepare to perform the instantiation process of non-lazy loading beans. See firstpreInstantiateSingletons
The first half of the method:
public void preInstantiateSingletons() throws BeansException { if (()) { ("Pre-instantiating singletons in " + this); } //Get the names of all beans List<String> beanNames = new ArrayList<>(); for (String beanName : beanNames) { //The operation of merging the BeanDefinition of the parent class has been performed //When you can configure beans with XML, there is a parent attribute that can inherit class names, scopes, etc. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!() && () && !()) { //Judge it is FactoryBean if (isFactoryBean(beanName)) { //If it is FactoryBean, add & Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (() != null && factory instanceof SmartFactoryBean) { isEagerInit = ((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { //The situation is not factoryBean getBean(beanName); } } } ...
First frombeanDefinitionNames
Get all the listbeanName
, perform traversal. Said beforeDefaultListableBeanFactory
A cached internallybeanDefinitionMap Map
, and thisbeanDefinitionNames
From this, it can also be seen that the workload in encoding can be reduced to a certain extent through appropriate redundancy.
Before initializing the bean, there are 3 conditions: cannot be loaded for abstract classes, singleton beans, and non-lazy. Very easy to understand, I won't say more, I will explain it carefullyisFactoryBean
Method to determine whether the bean isFactorybean
。Factorybean
It is a relatively special bean and is managed by spring container. Let's take a look at the interface definition:
public interface FactoryBean<T> { T getObject() throws Exception; Class<?> getObjectType(); default boolean isSingleton() { return true; } }
If a class is implementedFactoryBean
Interface, there will be two objects in that spring container, one isgetObject
The object returned by the method, the other one is the current oneFactoryBean
The object itself, and&
Add onbeanName
Make a distinction before. For example:
@Component public class MyFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { return new TestDao(); } @Override public Class<?> getObjectType() { return ; } }
test:
(("myFactoryBean")); (("&myFactoryBean"));
result:
@fbd1f6
@1ce24091
forFactoryBean
To obtain it,beanName
Prefix&
, and then you will first determine whether it isSmartFactoryBean
andisEagerInit
True, if so, callgetBean
The method is initialized. Skip the content here and look directly at the important onesgetBean
method:
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
Here is an empty method, continue to calldoGetBean
Method, starting from this, is the core process of instantiating beans.
Instantiated bean
For the convenience of analysis, we number the classes and methods according to the call Shunxun to facilitate the analysis of the subsequent analysis process.
1. DoGetBean method of AbstractBeanFactory
As before, non-focused content is explained directly in the code with comments.
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; //Try to get it from the spring container first, if it is empty, instantiate it Object sharedInstance = getSingleton(beanName); //Args is empty when calling getBean //If it is not empty, it means that the caller does not want to get the bean, but creates the bean if (sharedInstance != null && args == null) { if (()) { if (isSingletonCurrentlyInCreation(beanName)) { ("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { ("Returning cached instance of singleton bean '" + beanName + "'"); } } /* * If it is an ordinary singleton bean, the following method will directly return sharedInstance * But if it is of FactoryBean type, you need to get the bean instance * If you want to obtain FactoryBean itself, you won't do any special treatment. * */ bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //If the current thread has created this bean of prototype type, an exception will be thrown if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // If spring is not modified, the default parentBeanFactory is empty BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) (nameToLookup, args); } else { return (nameToLookup, requiredType); } } if (!typeCheckOnly) { //typeCheckOnly is false, added to the alreadyCreated Set collection, indicating that it has been created //Prevent duplicate creation markBeanAsCreated(beanName); } //The key part, create a singleton bean, or create a new prototype bean try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Determine whether the current bean has dependencies. Here it refers to the situation where depends-on is used. You need to instantiate the dependency bean first. String[] dependsOn = (); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException((), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } //Register dependency registerDependentBean(dep, beanName); try { //Initialization is dependent bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException((), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } //This is where the bean instance is really created if (()) { sharedInstance = getSingleton(beanName, () -> { try { //Sentences that really create functions return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // Create an instance of prototype else if (()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } //If it is not singleto and prototype, delegate to the corresponding implementation class to handle it. else { String scopeName = (); final Scope scope = (scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = (beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } //Exception is thrown, code is omitted... } //Type check, if normal, return, if exception is thrown if (requiredType != null && !(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, ()); } return convertedBean; } catch (TypeMismatchException ex) { if (()) { ("Failed to convert bean '" + name + "' to required type '" + (requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, ()); } } return (T) bean; }
Before creating the bean, the first call isDefaultSingletonBeanRegistry
ofgetSingleton
Method, that is, spring tries to obtain it once before initializing a bean, and determines whether the object has been instantiated. If it already exists, it will be used directly. EntergetSingleton
Method, core code:
Object singletonObject = (beanName);
Take a looksingletonObjects
Definition:
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
Here I will spoil it in advance. This map is used to store instantiated singleton beans, and in a narrow sense, it can be said thatsingletonObjects
It's the spring container, and it uses itConcurrentHashMap
to ensure the security of concurrent operations.
Because our bean is still in the creation stage, we will definitely not be able to obtain the instance from the map this time. Then run it down and take a look at the calledcreateBean
method.
2. The createBean method of AbstractAutowireCapableBeanFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (()) { ("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; //Make sure the Class in BeanDefinition is loaded Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !() && () != null) { mbdToUse = new RootBeanDefinition(mbd); (resolvedClass); } // Handle lookup-method and replace-method configurations // In spring, lookup-method and replace-method are collectively called method overrides try { (); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException((), beanName, "Validation of method overrides failed", ex); } try { //Application of post-processor, if the bean returned by post-processor is not empty, it will be returned directly Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException((), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } try {//Calling doCreateBean to create bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (()) { ("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } //Not important code omitted...}
I did a long preparation work before, but I still didn’t create a bean. The work of creating a bean was handed over todoCreateBean
The method is completed.
3. DoCreateBean method of AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { //BeanWrapper is a wrapper interface, and the real instantiation is BeanWrapperImpl BeanWrapper instanceWrapper = null; if (()) { instanceWrapper = (beanName); } if (instanceWrapper == null) { //Create a bean instance and wrap the instance in the BeanWrapper implementation class object to return instanceWrapper = createBeanInstance(beanName, mbd, args); } // Use BeanWrapper to generate a native object final Object bean = (); Class<?> beanType = (); if (beanType != ) { = beanType; } // Allow post-processors to modify the merged bean definition. synchronized () { if (!) { try { //Execute the postprocessor MergedBeanDefinitionPostProcessor applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException((), beanName, "Post-processing of merged bean definition failed", ex); } = true; } } // Used to deal with circular dependencies, and will be analyzed separately later boolean earlySingletonExposure = (() && && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (()) { ("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //Execute the postprocessor addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } //So far, it's still the native object Object exposedObject = bean; try { //Assign attributes and dependencies are very important populateBean(beanName, mbd, instanceWrapper); //Execute the postprocessor and become a proxy object. AOP is the process completed here. exposedObject = initializeBean(beanName, exposedObject, mbd); } //The intermediate non-important code is omitted... return exposedObject; }
Three more important tasks are done here:
- ①, call
createBeanInstance
Method to create bean instance - ②, call
populateBean
Fill the attributes, and dependency injection is done here. - ③, call
initializeBean
, execute various post-processors, execute various callback functions
In order, we will continue to talk about the process of creating bean forces in ①. After this process is finished, we will go back to analyze the attribute filling and callback methods.
4. The createBeanInstance method of AbstractAutowireCapableBeanFactory
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { //Make sure the class is loaded Class<?> beanClass = resolveBeanClass(mbd, beanName); //Detection of access permissions for a class spring is allowed to access public classes by default. if (beanClass != null && !(()) && !()) { throw new BeanCreationException((), beanName, "Bean class isn't public, and non-public access not allowed: " + ()); } Supplier<?> instanceSupplier = (); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } /* *If the factory method is not empty, build the bean object through the factory method * factoryMethod is based on xml and is rarely used in actual work * */ if (() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } /* * From the original comments of spring, you can know that this is a ShortCut. When the same bean is built multiple times, you can use this ShortCut * The resolved and the bean will be set during the first instantiation process. * */ boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized () { if ( != null) { resolved = true; //If the parameters of the constructor have been parsed, an example must be performed by a constructor with parameter autowireNecessary = ; } } } if (resolved) { if (autowireNecessary) { //Construct bean object through automatic assembly of construction method return autowireConstructor(beanName, mbd, null, null); } else { //By the default parameter-free construction method return instantiateBean(beanName, mbd); } } //Spring currently doesn't know how to instantiate this bean, so I first get all the construction methods //The postprocessor decides which constructors to return Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); /* * AUTOWIRE : 0-NO ,1-BY_NAME,2-BY_TYPE,3-CONSTRUCTOR * What you get here () is 0, which is NO * */ if (ctors != null || () == AUTOWIRE_CONSTRUCTOR || () || !(args)) { return autowireConstructor(beanName, mbd, ctors, args); } //Initialize using the default parameterless constructor return instantiateBean(beanName, mbd); }
If the bean has multiple construction methods, it will determine which one is used based on the parameters. The specific content is more complicated and will be prepared to be analyzed in a separate article later. If there is only a parameterless construction method or a construction method is not written, the parameterless construction method will be used by default for instantiation. This situation is only analyzed for the time being.
5. The instantiateBean method of AbstractAutowireCapableBeanFactory
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (() != null) { beanInstance = ((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { // getInstantiationStrategy gets the instantiation strategy of the class beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( (), beanName, "Instantiation of bean failed", ex); } }
Passed heregetInstantiationStrategy
Get the instantiation policy of the class, which by default is to get a reflected instantiation policy. Then callinstantiate
The method is instantiated.
6. SimpleInstantiationStrategy's instantiate method
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Check whether lookup-method or replace-method is configured in the bean configuration //If configured, you need to use CGLIB to build bean object if (!()) { Constructor<?> constructorToUse; synchronized () { constructorToUse = (Constructor<?>) ; if (constructorToUse == null) { final Class<?> clazz = (); if (()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (() != null) { constructorToUse = ( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { //Get the default constructor, even if it is not written, there will be one constructorToUse = (); } = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } //Instantiate using constructor method return (constructorToUse); } else { //Instantiation using CGLIB return instantiateWithMethodInjection(bd, beanName, owner); } }
instantiateClass
In the method,Create an object through reflection:
//Set the constructor to be accessible(ctor); //Reflection creates an objectreturn ((()) ? (ctor, args) : (args));
After running this, the instantiation process is completed, but the attribute has not been injected yet. Go back to the example we gave at the beginning, there is another Dao that has not been injected. In the next article, we will analyze the injection of the attributes next.
This is the article about Spring source code analysis Bean instantiation. For more relevant Spring Bean instantiation content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!