preface
Following on from the previous section, we continue to explore the source code of the getBean method
start
Last time we looked at the getSingleton method, let’s look at getObjectForBeanInstance(sharedInstance, Name, beanName, NULL); This code
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(transformedBeanName(name), beanInstance.getClass()); } } // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. if (! (beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. FactoryBean<? > factory = (FactoryBean<? >) beanInstance; // Caches object obtained from FactoryBean if it is a singleton. if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd ! = null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, ! synthetic); } return object; }Copy the code
As you can see, this method actually gets the bean instance in the cache, but it also determines if the bean is of type factoryBean and if the bean is a factoryBean itself, because a factoryBean is also a bean, but it has some special capabilities. As for factoryBean, it’s easy to confuse it with BeanFactory. I’ll write another article about the difference between factoryBean and BeanFactory sometime, but I won’t discuss it now.
Then, if there is no data in the cache, you go up to the beanFactory and try to get the bean, which ultimately ends up in the doGetBean method. If you don’t get the bean at the beanFactory, you come up to this code, which is very important
try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Check whether // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); 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) { // 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; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { 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; }Copy the code
There the final code RootBeanDefinition MBD = getMergedLocalBeanDefinition (beanName); To merge the parent attribute. What is the RootBeanDefinition? I found a person’s explanation on the Internet. I think it’s quite in place
// In a multi-inheritance system, RootBeanDefinition represents the BeanDefinition of the parent of the currently initializing class. If there is no parent, Public class RootBeanDefinition extends AbstractBeanDefinition {public class RootBeanDefinition extends AbstractBeanDefinition { //BeanDefinitionHolder stores Bean names, aliases, beanDefinition@nullable private BeanDefinitionHolder decoratedDefinition; @nullable Private AnnotatedElement qualifiedElement; // allowCaching Boolean allowCaching = true; Boolean isFactoryMethodUnique = false; // encapsulates java.lang.reflect.Type, which provides generics-related operations @nullable volatile ResolvableType targetType; @nullable volatile class <? > resolvedTargetType; @nullable Volatile ResolvableType factoryMethodReturnType; /** Common lock for the four constructor fields below */ final Object constructorArgumentLock = new Object(); / / the cache has been parsed Constructor or factory Method, the Executable is Method, type of the Constructor of the parent class @ Nullable the Executable resolvedConstructorOrFactoryMethod; / / that the constructor argument parsing over Boolean constructorArgumentsResolved = false; / / cache completely resolved the constructor parameter @ Nullable Object [] resolvedConstructorArguments; / / cache to parse the constructor parameters, which have not found the corresponding instance, can be understood as no dependent parameter @ Nullable Object [] preparedConstructorArguments; /** Common lock for the two post-processing fields below */ final Object postProcessingLock = new Object(); / / to indicate whether be treated MergedBeanDefinitionPostProcessor Boolean postProcessed = false; / / in the generated proxy will use, to indicate whether have been generated proxy @ Nullable volatile Boolean beforeInstantiationResolved; / / the type of the actual cache is the Constructor, Field, Method type @ Nullable private Set < Member > externallyManagedConfigMembers; // The name of the init callback function in InitializingBean -- afterPropertiesSet is recorded here, For lifecycle callback @ Nullable private Set < String > externallyManagedInitMethods; / / the destroy DisposableBean callback function name - destroy records here, for lifecycle callback @ Nullable private Set < String > externallyManagedDestroyMethods; @override public String getParentName() {return null; } @Override public void setParentName(@Nullable String parentName) { if (parentName ! = null) { throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference"); }} @nullable public class <? > getTargetType() { if (this.resolvedTargetType ! = null) { return this.resolvedTargetType; } ResolvableType targetType = this.targetType; return (targetType ! = null ? targetType.resolve() : null); } @Override public RootBeanDefinition cloneBeanDefinition() { return new RootBeanDefinition(this); }}Copy the code
After getMergedLocalBeanDefinition (beanName) this method gets the MBD, will have to check the MBD dependsOn, because of the need to control the bean’s loading sequence, If there is a dependsOn annotation, register the dependent bean first and then getBean. If there is no dependsOn annotation, then getBean is the most common bean. Then go to the code section that creates the bean instance
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; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);Copy the code
Call createBean method will eventually come to org. Springframework. Beans. Factory. Support. AbstractAutowireCapableBeanFactory# createBean (Java. Lang. Str Ing, org. Springframework. Beans. Factory. Support. RootBeanDefinition, Java. Lang. Object []) this method
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. Class<? > resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass ! = null && ! mbd.hasBeanClass() && mbd.getBeanClassName() ! = null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. Spring will the two configurations are collectively referred to as override method try {mbdToUse. PrepareMethodOverrides (); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try {// Apply the post-processing before the bean is initialized. If the bean returned by the post-processing is not empty, // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean ! = null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); Object beanInstance = doCreateBean(beanName, mbdToUse, args); // Call doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); }}Copy the code
The most important line of code in this method is Object beanInstance = doCreateBean(beanName, mbdToUse, args); This code is to create the bean instance, this method is very complex, involves the bean’s circular references, and properties of injection, the use of the post processor, and so on, these are beyond the scope of interpretation of the source code, not to speak in detail, I’ll post the code simply explain the main points which a few steps to create the instance of the bean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) {/** * returns by creating the bean instance and wrapping it in the BeanWrapper implementation class object. * createBeanInstance contains three ways to create bean instances: * 1. Create bean instances using factory methods * 2. Create bean instances using autowire by constructor * 3. Create a bean instance by using the no-argument constructor method * * If the bean configuration information is configured with lookup-method and replace-method, the bean instance is enhanced with CGLIB *. More on lookup-method and replace-method later. */ instanceWrapper = createBeanInstance(beanName, mbd, args); } final 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.isDebugEnabled()) { logger.debug("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 {// Set the property, very important populateBean(beanName, MBD, instanceWrapper); // Execute the post-processor, where aop is done to process 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, "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 " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }Copy the code
InstanceWrapper = createBeanInstance(beanName, MBD, args); instanceWrapper = createBeanInstance(beanName, MBD, args); To start this method, called after this method, we actually have been able to get the bean, but the beans are was packing up the bean wrapper classes, and then is set properties, perform the post processor, the execution of the post processor, the whole bean even if instantiation completed, finally returns to the getBean method, Add a cast to get the object.
conclusion
After the analysis of two articles, I believe that you have basically understood the execution process of getBean method and the meaning of those methods and methods called. At the same time, you are familiar with the Spring code style, which is constantly nested to call a lot of inheritance plus a lot of factories and a lot of overloaded methods. If I have time, I will also explain how Spring resolves the problem of bean circular reference, the difference between beanFactory and FactoryBean, property injection, bean post-processor, etc. I hope you pay attention to the source code, thank you.