First, we customize the two classes and make a circular reference to see the execution effect
- OrderServiceImpl
@Service public class OrderServiceImpl implements IOrderService { @Resource private IUserService userService; @Override public String getOrderById(Integer id) { return "order :"+id; } @Override public String getOrderByUser(Integer userId) { String user = userService.getUserById(userId); return user+"[order]"; } }
- UserServiceImpl
@Service public class UserServiceImpl implements IUserService { @Resource private IOrderService orderService; @Override public String getUsers() { return "list users:"+System.currentTimeMillis(); } @Override public String getUserById(Integer id) { return "user:"+id; } }
When starting, there is a problem of circular dependency. Why? Isn't Spring solved
It turned out to be the official release of springboot 2.6: circular dependency is prohibited by default. Spring. Main. Allow circular references = true needs to be added to solve the problem of circular dependency.
How does Spring solve the problem of circular dependency
populateBean entry
First, check when dependency fields are injected. We take OrderServiceImpl as an example. When initializing OrderServiceImpl, we first call getBean. When the doCreateBean is executed, after instantiation, dependency injection is carried out, and the populateBean method is called. In the populate method, when the instantiation package post processor is executed, Dependency injection is performed on the field modified by @ Resource annotation, which depends on CommonAnnotationBeanPostProcessor General annotation Bean post processor, populateBean after execution, continue to execute
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { 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) { instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } 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); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName,""); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
In the process of executing populateBean, there are two post processors of InstantiationAwareBeanPostProcessor type, but the execution method is different. Before pvs, the bp.postProcessAfterInstantiation method is called, that is, post processing method after instantiation. After pvs, bp.postProcessProperties is called post processing attribute method.
There are four post processors returned by getbeanpostprocessorcache(). Instantiaaware. This time, we mainly analyze the CommonAnnotationBeanPostProcessor processor
0 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@8267}
1 = {InfrastructureAdvisorAutoProxyCreator@5741} "proxyTargetClass=true; optimize=false; opaque=false; exposeProxy=false; frozen=false"
2 = {CommonAnnotationBeanPostProcessor@4834}
3 = {AutowiredAnnotationBeanPostProcessor@6728}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (bw == null) { if (mbd.hasPropertyValues()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. return; } } // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the // state of the bean before properties are set. This can be used, for example, // to support styles of field injection. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); int resolvedAutowireMode = mbd.getResolvedAutowireMode(); if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. 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 (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = bp.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); } if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); } } }
CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor has a member variable injectionMetadataCache that caches the fields that need to be injected by each Bean. The class name is key and the InjectionMetadata type object is the value, so the post processing attribute method gets the OrderServiceImpl dependent userService field from the cache and then invokes metadata's inject method. Return to calling the getResource method and randomly execute the [autowireResource] automatic assembly resource method.
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; } protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { // JNDI lookup to perform? String jndiName = null; if (StringUtils.hasLength(element.mappedName)) { jndiName = element.mappedName; } else if (this.alwaysUseJndiLookup) { jndiName = element.name; } if (jndiName != null) { if (this.jndiFactory == null) { throw new NoSuchBeanDefinitionException(element.lookupType, "No JNDI factory configured - specify the 'jndiFactory' property"); } return this.jndiFactory.getBean(jndiName, element.lookupType); } // Regular resource autowiring if (this.resourceFactory == null) { throw new NoSuchBeanDefinitionException(element.lookupType, "No resource factory configured - specify the 'resourceFactory' property"); } return autowireResource(this.resourceFactory, element, requestingBeanName); } private class ResourceElement extends LookupElement { protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); } } }
- InjectionMetadata
After getting the injection element, call the inject method, then call the field.set(target, getResourceToInject(target, requestingBeanName)) in InjectedElement, and then invoke getResourceToInject in CommonAnnotationBeanPostProcessor$ResourceElement to get the elements that need to be injected.
Randomly call getResource in CommonAnnotationBeanPostProcessor to inject dependency field.set according to the bean instance returned by getResource
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); } } } public abstract static class InjectedElement { protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); field.set(target, getResourceToInject(target, requestingBeanName)); } else { if (checkPropertySkipping(pvs)) { return; } try { Method method = (Method) this.member; ReflectionUtils.makeAccessible(method); method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } } }
autowireResource
Call in the autowireResource method beanFactory.resolveDependency Method, descriptor = [field:userService]; requestingBeanName=[orderServiceImpl]; autowiredBeanNames=[],
After BeanInstance is obtained through beanFactory.resolveDependency, continue to execute downward beanFactory.registerDependentBean (autowiredBeanName, requestingBeanName) method, register the dependent bean, and then return the resource object
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { Object resource; Set<String> autowiredBeanNames; //name = userService String name = element.name; if (factory instanceof AutowireCapableBeanFactory) { AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory; //descriptor= field:userService DependencyDescriptor descriptor = element.getDependencyDescriptor(); if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) { autowiredBeanNames = new LinkedHashSet<>(); resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null); if (resource == null) { throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); } } else { resource = beanFactory.resolveBeanByName(name, descriptor); autowiredBeanNames = Collections.singleton(name); } } else { resource = factory.getBean(name, element.lookupType); autowiredBeanNames = Collections.singleton(name); } if (factory instanceof ConfigurableBeanFactory) { ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory; for (String autowiredBeanName : autowiredBeanNames) { if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) { beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName); } } } return resource; } }
- registerDependentBean
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /** Map between dependent bean names: bean name to Set of dependent bean names. */ //The mapping between dependent beans and the collection of dependent classes corresponding to the injection class private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); /** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */ //The mapping between dependent beans and the collection of injection classes corresponding to dependent classes private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } } }
resolveDependency
After a series of judgments, enter the doResolveDependency resolution dependency method to obtain the matched beans that match the injected BeanClass. If the instance is a Class type, call the resolution candidate method of the field descriptor
descriptor.resolveCandidate After parsing the Class, we get the instance object from the level 3 cache. We continue to execute downward, return the result object, and execute the ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint) method in the finally method to set the current injection point as the previous injection point. Here, take OrderService and UserService as examples:
OrderServiceImpl is loaded for the first time, and the injection point is UserServiceImpl,
Then, when injecting UserServiceImpl, the roles are transferred to each other, the UserServiceImpl is loaded, and the injection point is OrderServiceImpl,
When the injection object is returned for the first time here, the injection point is OrderServiceImpl. After setCurrentInjectionPoint, the injection point becomes UserServiceImpl
Private static final namedthreadlocal currentinjectionpoint = new namedthreadlocal < > ("current injection point") local thread variable
Returns the instance to the previous level[autowireResource](#autowireResource) 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 { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); } else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); } else { Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } } public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { //Set the current field as the current injection point InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } //The current type resolved is type = com.bait.analyze.springdemo.service.iuserservice Class<?> type = descriptor.getDependencyType(); //The recommended value obtained is null Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); try { return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { // A custom TypeConverter which does not support TypeDescriptor resolution... return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } } //Resolve multiple beans, mainly for streamdependency descriptor, isArray, Collection and Map types Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } //Call the method to find automatic assembly candidates and return Class Map Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; //At this time, matchingBeans = 1, and there is exactly one that meets the conditions if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). return null; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // We have exactly one match. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); //autowiredBeanName = userServiceImpl //instanceCandidate = com.bail.analyse.springdemo.service.impl.UserServiceImpl autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } //If the instance is a Class type, the resolve candidate method of the field descriptor is called if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } result = null; } if (!ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass()); } return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } } }
- findAutowireCandidates
Beanfactoryutils.beannamesfortypeincludingprocessors (this, requiredtype, true, descriptor. Iseager()) method obtains the candidate name. In fact, it judges whether there is a candidate matching the injected field type according to the BeanDefinition type from the BeanDefinitionMap. If it is not a FactoryBean, call isTypeMatch () to judge whether the current BeanDefinition meets the candidates, and finally return a result = userserviceimpl - >{ Class@4416 } "class com.bail.analyse.springdemo.service.impl.UserServiceImpl"
protected Map<String, Object> findAutowireCandidates( @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) { //Get the name of the candidate. At this time, candidateNames = [userServiceImpl] String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this, requiredType, true, descriptor.isEager()); Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length); //The function here needs to be practiced for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) { Class<?> autowiringType = classObjectEntry.getKey(); if (autowiringType.isAssignableFrom(requiredType)) { Object autowiringValue = classObjectEntry.getValue(); autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType); if (requiredType.isInstance(autowiringValue)) { result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue); break; } } } for (String candidate : candidateNames) { //Here, judge whether the bean is not a self reference and whether the candidate meets the injection field, judge whether it meets the conditions, and enter the if logic if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) { //Add candidate key value pairs addCandidateEntry(result, candidate, descriptor, requiredType); } } if (result.isEmpty()) { boolean multiple = indicatesMultipleBeans(requiredType); // Consider fallback matches if the first pass failed to find anything... DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch(); for (String candidate : candidateNames) { if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) && (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) { addCandidateEntry(result, candidate, descriptor, requiredType); } } if (result.isEmpty() && !multiple) { // Consider self references as a final pass... // but in the case of a dependency collection, not the very same bean itself. for (String candidate : candidateNames) { if (isSelfReference(beanName, candidate) && (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) && isAutowireCandidate(candidate, fallbackDescriptor)) { addCandidateEntry(result, candidate, descriptor, requiredType); } } } } return result; } /** *Add an entry to the candidate mapping: bean instance (if available) or resolved only type, *To prevent bean initialization before the primary candidate selection. Enter the last else */ private void addCandidateEntry(Map<String, Object> candidates, String candidateName, DependencyDescriptor descriptor, Class<?> requiredType) { if (descriptor instanceof MultiElementDescriptor) { Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this); if (!(beanInstance instanceof NullBean)) { candidates.put(candidateName, beanInstance); } } else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor && ((StreamDependencyDescriptor) descriptor).isOrdered())) { Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this); candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance)); } else { candidates.put(candidateName, getType(candidateName)); } }
isTypeMatch
The method called Object beanInstance = getSingleton (beanName, false) to obtain the instance object from the singleton container, execute the predictBeanType(beanName, mbd, typesToMatch) method, predict the Bean type, return the original target type com.bait.analyze.springdemo.service.impl.userserviceimpl, and execute the typeToMatch.isAssignableFrom(predictedType) method to judge that the interface type is consistent with the implementation class, Return true
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name); // Check manually registered singletons.singletonObjects does not have a singleton object, and does not return null directly during creation //Obtain the instance object from the singleton container. At this time, beanName = userServiceImpl; Object beanInstance = getSingleton(beanName, false); if (beanInstance != null && beanInstance.getClass() != NullBean.class) { if (beanInstance instanceof FactoryBean) { if (!isFactoryDereference) { Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance); return (type != null && typeToMatch.isAssignableFrom(type)); } else { return typeToMatch.isInstance(beanInstance); } } else if (!isFactoryDereference) { if (typeToMatch.isInstance(beanInstance)) { // Direct match for exposed instance? return true; } else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) { // Generics potentially only match on the target class, not on the proxy... RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); Class<?> targetType = mbd.getTargetType(); if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) { // Check raw class match as well, making sure it's exposed on the proxy. Class<?> classToMatch = typeToMatch.resolve(); if (classToMatch != null && !classToMatch.isInstance(beanInstance)) { return false; } if (typeToMatch.isAssignableFrom(targetType)) { return true; } } ResolvableType resolvableType = mbd.targetType; if (resolvableType == null) { resolvableType = mbd.factoryMethodReturnType; } return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType)); } } return false; } else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) { // null instance registered return false; } // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch); } // Retrieve corresponding bean definition. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); // Setup the types that we want to match against Class<?> classToMatch = typeToMatch.resolve(); if (classToMatch == null) { classToMatch = FactoryBean.class; } Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ? new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch}); // Attempt to predict the bean type Class<?> predictedType = null; // We're looking for a regular reference but we're a factory bean that has // a decorated bean definition. The target bean should be the same type // as FactoryBean would ultimately return. if (!isFactoryDereference && dbd != null && isFactoryBean(beanName, mbd)) { // We should only attempt if the user explicitly set lazy-init to true // and we know the merged bean definition is for a factory bean. if (!mbd.isLazyInit() || allowFactoryBeanInit) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class<?> targetType = predictBeanType(dbd.getBeanName(), tbd, typesToMatch); if (targetType != null && !FactoryBean.class.isAssignableFrom(targetType)) { predictedType = targetType; } } } // If we couldn't use the target type, try regular prediction. if (predictedType == null) { predictedType = predictBeanType(beanName, mbd, typesToMatch); if (predictedType == null) { return false; } } // Attempt to get the actual ResolvableType for the bean. ResolvableType beanType = null; // If it's a FactoryBean, we want to look at what it creates, not the factory class. if (FactoryBean.class.isAssignableFrom(predictedType)) { if (beanInstance == null && !isFactoryDereference) { beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit); predictedType = beanType.resolve(); if (predictedType == null) { return false; } } } else if (isFactoryDereference) { // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean // type but we nevertheless are being asked to dereference a FactoryBean... // Let's check the original bean class and proceed with it if it is a FactoryBean. predictedType = predictBeanType(beanName, mbd, FactoryBean.class); if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) { return false; } } // We don't have an exact type but if bean definition target type or the factory // method return type matches the predicted type then we can use that. if (beanType == null) { ResolvableType definedType = mbd.targetType; if (definedType == null) { definedType = mbd.factoryMethodReturnType; } if (definedType != null && definedType.resolve() == predictedType) { beanType = definedType; } } // If we have a bean type use it so that generics are considered if (beanType != null) { return typeToMatch.isAssignableFrom(beanType); } // If we don't have a bean type, fallback to the predicted type return typeToMatch.isAssignableFrom(predictedType); } }
- getSingleton
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { // Consistent creation of early reference within full singleton lock singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } } } return singletonObject; } }
- predictBeanType
In the prediction type method, the post processor of SmartInstantiationAwareBeanPostProcessor type is executed, that is, the intelligent instantiation aware Bean post processor; Two post processors are included here
0 = {InfrastructureAdvisorAutoProxyCreator@5741}
1 = {AutowiredAnnotationBeanPostProcessor@6728}
At this time, the two post processors are null processing, in which the infrastructure advisor autoproxycreator is not a real null processing, but performs logical null processing, that is, execution does not meet the conditions; The AutowiredAnnotationBeanPostProcessor defaults to null processing, and the predictBeanType method returns the original target type
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { @Nullable protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch); // Apply SmartInstantiationAwareBeanPostProcessors to predict the // eventual type after a before-instantiation shortcut. if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { boolean matchingOnlyFactoryBean = typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class; for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) { Class<?> predicted = bp.predictBeanType(targetType, beanName); if (predicted != null && (!matchingOnlyFactoryBean || FactoryBean.class.isAssignableFrom(predicted))) { return predicted; } } } return targetType; } }
descriptor
In fact, the getBean method of BeanFactory is called. beanName = userServiceImpl, enter a new loop to obtain the instance object of IUserService, and then execute the populateBean method as above,
In the populateBean method, execute the postProcessProperties method of the instantiation notification postprocessor instantiawarebeanpostprocessor. Execute the injectionMetadataCache method of CommonAnnotationBeanPostProcessor. At this time, the field that UserServiceImpl depends on is cached in the injection cache: orderService. Go through the same process as above, and finally execute the descriptor.resolveCandidate method, that is, the current method, and then enter the process of get Bean ("orderServiceImpl"). In the process of obtaining the beans of orderServiceImpl for the first time, from the doCreateBean() method to the populateBean, we executed several methods to preprocess the instantiated but uninitialized beans, respectively: earlySingletonExposure At this point, we get the instance object from the L3 cache and return to resolveDependency Continue dependency injection
public class DependencyDescriptor extends InjectionPoint implements Serializable { public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException { return beanFactory.getBean(beanName); } }
- AbstractBeanFactory
We continue to analyze the getBean() method. When we execute the doGetBean method, we call the getSingleton(beanName) method again. At this time, after the first addSingletonFactory method processing, the exposedObject already exists in the L3 cache, so we can directly return the instance object of orderServiceImpl. After obtaining the exposed object from the L3 cache, The obtained instance object is put into the L2 cache and the factory object is removed from the L3 cache.
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { // Consistent creation of early reference within full singleton lock singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } } } return singletonObject; } }
- AbstractBeanFactory
At this time, after the three-level cache function, the sharedInstance is not empty. Enter the if to continue execution getObjectForBeanInstance , after returning beanInstance, we will not continue to perform the operations in else, which will be omitted here. Then execute the adaptBeanInstance method.
adaptBeanInstance checks the type of BeanInstance. If it does not meet the type, it will perform a type strong conversion action. If the conversion fails, an error will be reported. Otherwise, the original instance object is returned directly. Return to the [descriptor.resolveCandidate]#(descriptor) method to continue field dependency injection.
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object beanInstance; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); //At this time, sharedInstance is not empty. Enter if to continue execution if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } //Call getObjectForBeanInstance to get the bean instance beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: . . . . . . } //Adaptive instance object return adaptBeanInstance(name, beanInstance, requiredType); } <T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) { // Check if required type matches the type of the actual bean instance. if (requiredType != null && !requiredType.isInstance(bean)) { try { //Type forced rotation action. If the conversion fails, an error will be reported Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return (T) convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; } }
earlySingletonExposure
If the singleton object is allowed to be exposed early, the method of adding a singleton factory is used to allow the dependent class to obtain the exposed instance object exposedObject from the early singleton factory when obtaining the dependent class
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) { exposedObject = bp.getEarlyBeanReference(exposedObject, beanName); } } return exposedObject; } }
addSingletonFactory mainly handles the level-3 cache. First, lock the singleton container, and then judge that if the current instance object does not exist in the container, add the object returned by lambda expression in singletonFactories cache, remove the object in early earlySingletonObjects, and add the name of the current bean in the registered singleton container.
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /**Name of the Bean being created */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** Singleton factory cache container: Bean name of the object factory */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Early singleton object cache container: Bean name of instance Bean */ private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); /** Registered singleton object name collection, Bean names saved in registration order */ private final Set<String> registeredSingletons = new LinkedHashSet<>(256); protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } }
getObjectForBeanInstance
After calling the getObjectForBeanInstance of AbstractAutowireCapableBeanFactory, continue to call the getObjectForBeanInstance method of the parent class AbstractBeanFactory, and return the original instance object by default
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { //currentlyCreatedBean is a local thread variable private final NamedThreadLocal<String> currentlyCreatedBean = new NamedThreadLocal<>("Currently created bean"); @Override protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { //The currentlycreatedbean obtained at this time = null, here String currentlyCreatedBean = this.currentlyCreatedBean.get(); if (currentlyCreatedBean != null) { registerDependentBean(beanName, currentlyCreatedBean); } return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd); } } public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } if (mbd != null) { mbd.isFactoryBean = true; } return beanInstance; } }
What does currentlyCreatedBean do?
after populateBean->UserServiceImpl
When the singleton object is allowed to be exposed early, after the populateBean is finished, call the getSingleton() method again. At this time, allowrearlyreference = false, beanName is userServiceImpl, and the cache object of userServiceImpl is in the L3 cache, but allowrearlyreference = false, Therefore, userServiceImpl can only obtain instance objects from the SingletonObjects cache of the first level cache and the earlySingletonObjects cache of the second level cache. The return must be null, indicating that the current instance is not an early exposed instance, but an instance that has been successfully initialized. Unlike orderServiceImpl, it is obtained from the third level cache. It is a one-step approach to generate successful.
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { ...... //earlySingletonExposure = true boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); ...... if (earlySingletonExposure) { //At this point, earlysingletonreference = null 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); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. //Register the bean as one-time destruction, and the default logical execution is null try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } }
getSingleton
After singletonFactory.getObject() returns the created singleton object, first call the afterSingletonCreation(beanName) method in finally to judge whether to exclude checking the creation status and removing the current bean name from the created bean object collection. Then call the addSingleton() method to put the singleton object into the L1 cache and remove it from the L2 and L3 cache.
Call the addSingleton() method
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } ...... finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } } //Judge whether to exclude checking the creation status and removing the current bean name from the created bean object collection protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } } //Put the singleton object into the L1 cache and remove it from the L2 and L3 cache. 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); } } }
doGetBean
After calling getSingleton to return to beanInstance, continue to call getObjectForBeanInstance(sharedInstance, name, beanName, mbd) to process, then call beanCreation.end() method and adaptBeanInstance to type strongly. Return object
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object beanInstance; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { ..... // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } . . . . . . } catch (BeansException ex) { beanCreation.tag("exception", ex.getClass().toString()); beanCreation.tag("message", String.valueOf(ex.getMessage())); cleanupAfterBeanCreationFailure(beanName); throw ex; } finally { beanCreation.end(); } } return adaptBeanInstance(name, beanInstance, requiredType); } }
after populateBean->OrderServiceImpl
The difference between OrderServiceImpl and UserServiceImpl is that OrderServiceImpl is obtained from the three-level cache in the process of circular dependency. Therefore, when it is obtained from the cache after populateBean, the instance object exposed in advance is obtained,
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { 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) { instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. ...... // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { } if (earlySingletonExposure) { //At this time, the object exposed in advance is obtained, Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { //If the exposed Bean and the injected Bean are one object, it means that the Bean has not changed, so assign the early exposed object to the exposed object if (exposedObject == bean) { exposedObject = earlySingletonReference; } //Otherwise, the bean changes during the populate process and needs to be processed 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); } } if (!actualDependentBeans.isEmpty()) { } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; } }
if (exposedObject == bean) {}else {} what scenario will it appear?
At this point, a simple circular dependency process is sorted out. Of course, there are other scenes, see the next chapter! [17749s]
Reference code