How does spring solve circular dependency

Posted by shai1 on Sun, 27 Feb 2022 14:20:45 +0100

In the previous article Analysis of the whole process of using hystrix from feign In, the workflow of springboot startup is explained in detail through a figure. I haven't enjoyed it yet. Today, I will analyze the instantiation process of beans and how spring solves circular dependency in detail. The following figure related to bean instantiation is slightly supplemented.

Refresh refresh

  • Invokebeanfactoryprocessors process beanFactory

  • First, the configclass is parsed (all metadata is parsed)

  • Load beanDefinition from resources and Registrar

  • finishBeanFactoryInitialization

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
		    ......
		    finishBeanFactoryInitialization(beanFactory);
		    ......
		}
		    
	}	
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    	//The beanFactory here is DefaultListableBeanFactory
	    beanFactory.preInstantiateSingletons();	    
	}
}

In the DefaultListableBeanFactory, the getBean is booted

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	@Override
	public void preInstantiateSingletons() throws BeansException {
	    //beanDefinitionNames is the beanName registered after parsing
	    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
	    for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
				    //Special handling for FactoryBean
				} else {
				    //Focus on
					getBean(beanName);
				}
			}
		}
			
	}    
}

Let's take a look at AbstractBeanFactory and the class relationship

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	@Override
	public Object getBean(String name) throws BeansException {
	    //From getBean to doGetBean
		return doGetBean(name, null, null, false);
	}  
	protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {
	    //① Get the singleton class from the cache (focus on reading)
	    Object sharedInstance = getSingleton(beanName);	    
	    if (sharedInstance != null && args == null) {
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	    } else {
    		//If it is a circular reference of multiple cases, throw the exception directly
    		if (isPrototypeCurrentlyInCreation(beanName)) {
    			throw new BeanCurrentlyInCreationException(beanName);
    		}
    		//Other processing
    		
		}
		if (!typeCheckOnly) {
		    //Tag bean creation
			markBeanAsCreated(beanName);
		}
		try {
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			if (mbd.isSingleton()) {
			   // ② Get singleton bean (focus on writing)
				sharedInstance = getSingleton(beanName, () -> {
					try {
					    //Create a bean, an anonymous method, which is called in getSingleton
						return createBean(beanName, mbd, args);
					}
				});
				//bean fetch
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
		}catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
		return (T) bean;

	}
}

In the above code, there are two

  • One is to ① get the singleton class from the cache (focusing on reading), getSingleton(beanName);

  • It's meaningless to just look here. It should be combined with the creation process.

  • ② get the singleton bean (focus on writing), and finally follow the createBean logic in the anonymous method

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    //① Cache the mapping of singleton object, bean name and instance
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	//② Cache the factory of the singleton object, and the mapping of the bean name and the corresponding factory
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    //③ Cache the early singleton object. After instantiation, the uninitialized cache (in spring, it is in the state of being created)
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);	
	//④ The collection of registered singleton instances has only bean name
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
	//⑤ Cache of bean being created, set collection
	private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    //Focus on reading
	@Override
	@Nullable
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
	//Pay attention to reading. Here is the widely circulated three-level cache
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		//At this time, get the instance from ① and return it directly, which is the so-called first level cache
		Object singletonObject = this.singletonObjects.get(beanName);
		// When the instance is not obtained and is being created
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
	        //At this time, get the bean instance from earlySingletonObjects
			singletonObject = this.earlySingletonObjects.get(beanName);
			/Still no instance was obtained, allowEarlyReference Incoming is true
			if (singletonObject == null && allowEarlyReference) {
			    //Lock the singletonObjects at this time
				synchronized (this.singletonObjects) {
					// Double check. Get it again from ① at this time
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
					    // Double check. Get it again from ③ at this time
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
						    //Get the Bean Factory from ②
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
							    //If it is not empty, it will be put into ③ and removed from ② at the same time
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}
	//Focus on creating
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		//Lock the singletonObjects of the current object
		synchronized (this.singletonObjects) {
		    //Check again for
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
			    //It will be put into ⑤ here
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
				    //Obtain the object through the factory, which is the return createBean(beanName, mbd, args) in the anonymous method;
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
				    //If the creation is successful, continue to execute. If the exception is thrown, don't go down
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}

				finally {
					//It will be removed from ⑤ here
					afterSingletonCreation(beanName);
				}
				//After successful creation, it will be removed from singletonFactories and earlySingletonObjects
				if (newSingleton) {
				    //This will be put into ① and ④ and removed from ② and ③
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}	
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

The final code points to the doCreateBean in AbstractAutowireCapableBeanFactory, which can be said to be the core of spring to create a singleton. It can be divided into three steps:

  • ① createBeanInstance creates an instance (internal reflection mechanism)
  • Here is another key point: active cache addSingletonFactory, which will be added to the cache
  • ② populateBean automatic attribute filling
  • ③ Initialize bean initializeBean

Operation mechanism of L3 cache

From the above, we can see that after the instance is created, spring will add the object to the cache, and then do dependency filling and initialization

The specific codes are as follows:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {
		RootBeanDefinition mbdToUse = mbd;

		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		try {
			//Before instantiation, BeanPostProcessors have the opportunity to return a proxy object
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}

		try {
		    //Where beans are created without BeanPostProcessors intervention
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			return beanInstance;
		}
	}

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
		    //① Create bean instance
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allows post processors to modify the merged bean definition
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				mbd.postProcessed = true;
			}
		}

		// Actively cache singletons to resolve circular references
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
		    //Here, it will be written to ② ④ of DefaultSingletonBeanRegistry and removed from ③, where the cache is formed
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initializing an instance of a bean
		Object exposedObject = bean;
		try {
		    //② Attribute filling
			populateBean(beanName, mbd, instanceWrapper);
			//③ Initialize bean
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
			}
		}

		return exposedObject;
	}
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
        //Omit a bunch of special treatment
        //Handle when there is an object to be injected in the constructor
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// There is no special treatment, and the parameterless constructor is used for instantiation
		return instantiateBean(beanName, mbd);
	}	
	protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged(
						(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
						getAccessControlContext());
			}
			else {
			    //Using cglibsubclassing instantiationstrategy
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}
	//Attribute filling
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

		//Give instantiaawarebeanpostprocessors the opportunity to modify the state of the bean, especially the injection of fields, before setting the properties
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		//Resolve Autowire. At this time, the dependent object may not have been instantiated
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Injection by name
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// By type injection
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//Attribute resolution
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

        //Finally, attribute injection is completed
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
		    //Implement the method of realizing Aware interface
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
		    //Call the before method before instantiation
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
		    //Call the init method method
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
		    //Call after method
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
	protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			if (containsBean(propertyName)) {
			    //To getBean according to the attribute name, the logic is very simple, which directly starts the injected getBean process
				Object bean = getBean(propertyName);
				pvs.add(propertyName, bean);
				registerDependentBean(propertyName, beanName);
			}
		}
	}
	protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}

		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			try {
			    //Resolved attribute type
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
			    //Only objects of non Object type can be injected
				if (Object.class != pd.getPropertyType()) {
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					// Do not allow eager init for type matching in case of a prioritized post-processor.
					boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//It is complicated to resolve the dependent beans here. The resolveDependency is DefaultListableBeanFactory
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
						pvs.add(propertyName, autowiredArgument);
					}
					for (String autowiredBeanName : autowiredBeanNames) {
						registerDependentBean(autowiredBeanName, beanName);
						if (logger.isTraceEnabled()) {
							logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
									propertyName + "' to bean named '" + autowiredBeanName + "'");
						}
					}
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
			}
		}
	}
}

spring takes over the class loading process through its own mechanism, and automatically loads dependent properties through configuration.
ps: a flow chart of class loading is attached:

The following code is instantiated through reflection

public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
    
}
public class SimpleInstantiationStrategy implements InstantiationStrategy {
    @Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			//Omit get class constructor
			//Specify constructor instantiation class through BeanUtils
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}
}

public abstract class BeanUtils {
    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
			if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
				return KotlinDelegate.instantiateClass(ctor, args);
			}
			else {
				Class<?>[] parameterTypes = ctor.getParameterTypes();
				Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
				Object[] argsWithDefaultValues = new Object[args.length];
				for (int i = 0 ; i < args.length; i++) {
					if (args[i] == null) {
						Class<?> parameterType = parameterTypes[i];
						argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
					}
					else {
						argsWithDefaultValues[i] = args[i];
					}
				}
				//Notice here that ctor is a constructor and instantiated through reflection
				return ctor.newInstance(argsWithDefaultValues);
			}
		}
}

Property population code trace

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    //Attribute resolution
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}
	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
				element.inject(target, beanName, pvs);
			}
		}
	}
	private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				try {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					value = resolveFieldValue(field, bean, beanName);
				}
			}
			else {
				value = resolveFieldValue(field, bean, beanName);
			}
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}	
		@Nullable
		private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			Object value;
			try {
			    //Back to BeanFactory
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			synchronized (this) {
				if (!this.cached) {
					Object cachedFieldValue = null;
					if (value != null || this.required) {
						cachedFieldValue = desc;
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
								cachedFieldValue = new ShortcutDependencyDescriptor(
										desc, autowiredBeanName, field.getType());
							}
						}
					}
					this.cachedFieldValue = cachedFieldValue;
					this.cached = true;
				}
			}
			return value;
		}
	}
	}
}

public class InjectionMetadata {
    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
				element.inject(target, beanName, pvs);
			}
		}
	}
}

autowireByType code trace

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
	    //analysis
	    result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);		   
	    return result;
	}
	@Nullable
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
         
			if (instanceCandidate instanceof Class) {
			    //Type type resolution
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}
}

Finally, getBean is returned in the DependencyDescriptor

public class DependencyDescriptor extends InjectionPoint implements Serializable {
    public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)throws BeansException {
        //Finally, it returns to getBean
		return beanFactory.getBean(beanName);
	}
}

A conclusion can be drawn from the above. When injecting through Autowire, if beanName is not specified, the cost is still relatively high.

To sum up:

  • After the instantiation is completed, spring adds the instance to the cache;
  • Then, dependency injection is adopted. At this time, the non instantiated classes are not in the cache, and they will go directly to doCreateBean;
  • When it has been created, it will be returned directly when getBean is created, and doCreateBean will not be executed
  • Through such a mechanism, the circular dependency is solved.

Topics: Java Spring Spring Boot source code analysis