1. SpringIoc can be divided into two stages

  1. Load resources. The resources here are mainly configuration information (XML files, @bean annotations, etc.), mainly throughResource.ResourceLoader2 big tools for loading and parsing.With the ResourceMainly responsible for resource positioning,ResourceLoader is responsible for loading resourcesAfter going through these two steps,The configuration information is assembled into a BeanDefinitionAnd saved inBeanDefinitionRegistryIn the.
  2. Load the beans. After the first step, Spring has converted the configuration information into beansBeanDefinitionRegistrygetBean()Method triggers the bean to load. This series of articles mainly explains the second step of the detailed process, the first step temporarily ignored, mind fat friends can baidu

2 The loading process starts

2.1 getBean ()

The source code is as follows, the code is very long, fat friends do not be afraid, we step by step analysis ha

public Object getBean(String name) throws BeansException {  
    return doGetBean(name, null, null, false); 
}
Copy the code
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, Throws BeansException {//1 Get beanName, Alias and FactoryBean "&" final String beanName = transformedBeanName(name); Object bean; // get bean Object sharedInstance = getSingleton(beanName); if (sharedInstance ! = null &&args == null) {//3 Remove useless logging code through getObjectForBeanInstance to get bean instance bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else {/ / 4 check the archetypal pattern of the if (isPrototypeCurrentlyInCreation (beanName)) {throw new BeanCurrentlyInCreationException(beanName); BeanFactory parentBeanFactory = getParentBeanFactory(); beanBeanFactory = 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) parentBeanFactory.getBean(nameToLookup, args); } else { return parentBeanFactory.getBean(nameToLookup, requiredType); }} // 6 record bean already created if (! typeCheckOnly) { markBeanAsCreated(beanName); } try {// 7 beanName the corresponding GenericBeanDefinition, and convert to RootBeanDefinition, And carries on the detection of final RootBeanDefinition MBD = getMergedLocalBeanDefinition (beanName); checkMergedBeanDefinition(mbd, beanName, args); String[] dependsOn = mbd.getSon (); if (dependsOn ! = null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); If (mbd.issingleton ()) {sharedInstance = getSingleton(beanName); () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) {// 10 Run the destroySingleton(beanName) if the creation fails (singleton mode may have exposed the bean in advance to resolve loop dependencies); throw ex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isprototype ()) {Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else {// 12 other scope String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); }}); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; If (requiredType! = null && ! requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }Copy the code

2.1.1 transformedBeanName(name)

First attach the source code

protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } public static String transformedBeanName(String name) {assert. notNull(name, "'name' must not be null"); String beanName = name; while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } return beanName; } // convert aliasName public String canonicalName(String name) {String canonname = name; String resolvedName; do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName ! = null) { canonicalName = resolvedName; } } while (resolvedName ! = null); return canonicalName; }Copy the code
  1. Remove the FactoryBean&At the beginning
  2. Convert aliases. Spring relies on HashMap to manage aliases in the aliasName -> beanName format. Multiple aliases also exist, so there is a loop untilresolvedName = null, indicates that the finalbeanName

2.1.2 getSingleton(beanName)

public Object getSingleton(String beanName) { return getSingleton(beanName, true); } protected Object getSingleton(String beanName, Boolean allowEarlyReference) {/ / 1 loading beans from the singleton cache Object singletonObject = this. SingletonObjects. Get (beanName); / / 2 cache the bean is empty && bean is creating the if current (singletonObject = = null && isSingletonCurrentlyInCreation (beanName)) {/ / synchronization locks Synchronized (this.singletonObjects) {// Obtain singletonObjects from earlySingletonObjects = synchronized this.earlySingletonObjects.get(beanName); // earlySingletonObjects does not have, If (singletonObject == null && allowEarlyReference) {// Retrieve the corresponding ObjectFactory from singletonFactories ObjectFactory<? > singletonFactory = this.singletonFactories.get(beanName); // if (singletonFactory! = null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; } public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); }Copy the code
  1. First of all, from thesingletonObjectsAccess to the bean
  2. ifsingletonObject == nullAnd the bean is being created
  3. Add synchronization lock, and then fromearlySingletonObjectsGet in,
  4. ifsingletonObjectOr null, and allows preloading, then fromsingletonFactoriesTo deriveObjectFactory<? > singletonFactoryAnd then through the factory methodsingletonFactory.getObject()To obtainsingletonObjectAnd join theearlySingletonObjects, fromsingletonFactoriesremove
  5. singletonsCurrentlyInCreationIt is used to determine whether the bean is in the process of creation. It is safe to guess that all beans will be added to the Map at the initial stage of creation. The answer will be revealed later in the article

There are three maps. Let’s examine each one

The name of the function
singletonObjects The storage relationship is beanName-> bean instance, which stores the singleton bean
earlySingletonObjects The storage relationship is beanName->bean instance, which andsingletonObjectsIs the difference between thesingletonObjectsIs the complete bean instance to store,earlySingletonObjectsStoring early beans is not necessarily complete (because Spring allows early exposure, which is key to resolving loop dependencies)
singletonFactories The relationship is beanName-> BeanFactory, which holds the factory of the singleton bean

2.1.3 getObjectForBeanInstance

protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @ Nullable RootBeanDefinition MBD) {/ / 1 factory class under the reference of some judgment if (BeanFactoryUtils. IsFactoryDereference (name)) {/ / if NullBean, If (beanInstance instanceof NullBean) {return beanInstance; } // 2 If beanInstance is not of type FactoryBean, throw an exception, double check? Because the front has done a judgment, can walk into this if ah if (! (beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); }} // 3 At this point we get a bean instance or a FactoryBean instance. If it's a FactoryBean, we create the bean if (! (beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } //4 Load FactoryBean Object Object = null; / / if BeanDefinition is null, then loaded from the cache if (MBD = = null) {object = getCachedObjectForFactoryBean (beanName); If (object == null) {FactoryBean<? > factory = (FactoryBean<? >) beanInstance; // if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } // Is the user defined rather than the application itself defined Boolean synthetic = (MBD! = null && mbd.isSynthetic()); Object = getObjectFromFactoryBean(factory, beanName,! synthetic); } return object; } protected Object getCachedObjectForFactoryBean(String beanName) { return this.factoryBeanObjectCache.get(beanName); }Copy the code
  1. For the factory Bean (to&), if NullBean, return,
  2. After a score of 1, an exception is returned if it is not a factory Bean
  3. At this point, we get an instance of a bean, either a normal bean or a FactoryBean

If BeanDefinition is null, the factoryBeanObjectCache obtains the BeanDefinition from factoryBeanObjectCache. The core method is again getObjectFromFactoryBean

2.1.4 getObjectFromFactoryBeanGet beans from the FactoryBean factory

protected Object getObjectFromFactoryBean(FactoryBean<? > factory, String beanName, Boolean shouldPostProcess) {// 1 isSingleton and contains if (factory.issingleton () &&containssingleton (beanName)) {synchronized (getSingletonMutex ()) {/ / 2 from the cache access to the specified factoryBean Object Object = this. FactoryBeanObjectCache. Get (beanName); If (object = = null) {/ / 3 is empty, is obtained from the FactoryBean object object = doGetObjectFromFactoryBean (factory, beanName); / / from factoryBeanObjectCache cache access Object alreadyThere = this. FactoryBeanObjectCache. Get (beanName); // If (alreadyThere! = null) { object = alreadyThere; } else {/ / 4 to subsequent processing the if (shouldPostProcess) {/ / if the bean is created in return bean if (isSingletonCurrentlyInCreation (beanName)) { return object; } // 5 beforeSingletonCreation(beanName); Try {/ / the object that was obtained from the FactoryBean post-processing object = postProcessObjectFromFactoryBean (object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally {// 6 afterSingletonCreation(beanName); }} / / 7 to cache the if (containsSingleton (beanName)) {this. FactoryBeanObjectCache. Put (beanName, object); } } } return object; }} else {/ / 8 a singleton Object Object = doGetObjectFromFactoryBean (factory, beanName); if (shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; }}Copy the code
  1. Check if it is singleton mode and singleton cachecontainsSingletonThere is the beanName
  2. throughfactoryBeanObjectCacheGets the specified factoryBean
  3. iffactoryBeanIf it is null, it passesdoGetObjectFromFactoryBeanthroughFactoryBean.getObject()Get factoryBean
  4. Determine whether follow-up operations are required
  • throughbeforeSingletonCreationCreate before processing, the code is as follows. Tap on the blackboard. It’s right heresingletonsCurrentlyInCreationAdd operation oh
protected void beforeSingletonCreation(String beanName) { if (! this.inCreationCheckExclusions.contains(beanName) && ! this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }}Copy the code

– postProcessObjectFromFactoryBean () to obtain the bean instance objects from FactoryBean post processing, the default implementation is directly return to the object. AbstractAutowireCapableBeanFactory to rewrite, let’s see the code, specific follow-up added

protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
}

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}
Copy the code
  • afterSingletonCreationPost-creation processing
protected void afterSingletonCreation(String beanName) { if (! this.inCreationCheckExclusions.contains(beanName) && ! this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); }}Copy the code
  1. Join the FactoryBeans