• Spring Reading Directory

We’ve read some of the source code for getBean in the last article. If you get an instance from the singleton pool, you check whether that instance is a FactoryBean. If it is a FactoryBean, then all you really need to get is the object returned by getObject. Moving on, what does Spring do if it doesn’t get an instance from the singleton pool?

The singleton pool did not get the Bean

// The code above is omitted --
// The singleton pool did not get the Bean
		else {
			// Specifies whether the prototype bean is being created. If so, throw an exception
			Spring does not support cyclic dependencies for prototype beans
			/ / the current is creating the prototype of the Bean will be placed in the ThreadLocal prototypesCurrentlyInCreation
            / / 1.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
            / / 2,
			// Get the parent BeanFactory
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// The parent of the current container exists and there is no BeanDefinition in the current container.
			if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
				// Resolve the user-specified bean name to the canonical name, concatenating the ampersand
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					// recursive search
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if(args ! =null) {
					// Delegation to parent with explicit args.
					// There are arguments, which delegate to the parent to find according to the specified name and explicit arguments
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if(requiredType ! =null) {
					// No args -> delegate to standard getBean method.
					// No arguments -> delegate to the parent to look up by the specified name and type
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					// Delegate the parent to search by the specified name.
					return(T) parentBeanFactory.getBean(nameToLookup); }}/ / 3.
			// Marks the specified bean as created (or to be created).
			// typeCheckOnly The upper input is false
			Hasbeandefinitionreader () hasBeanCreationStarted()
			// The markBeanAsCreated method adds data to the alreadyCreated Set
			if(! typeCheckOnly) { markBeanAsCreated(beanName); }try {
                / / 4.
				// Get the combined RootBeanDefinition
				// If the specified BeanName is a child Bean, the attributes of the parent class will be merged
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// Check the given merge bean definition
				checkMergedBeanDefinition(mbd, beanName, args);
				// Ensure that the bean on which the current bean depends is initialized. First load the bean specified by DependsOn
				/ / XML notation
			//<bean class="com.gongj.bean.Person" id="person" depends-on="user"></bean>
			//<bean class="com.gongj.bean.User" id="user" depends-on="person"></bean>
                
				// Note writing
				//@DependsOn("user")
                
				// Get the names of all dependent beans of the current Bean. For example, the current beanName is A, which depends on B
				String[] dependsOn = mbd.getDependsOn(); DependsOn is a dependsOn for B
				if(dependsOn ! =null) {
					for (String dep : dependsOn) {
						// Check whether beanName(A) is also dependent on deP (B)
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// There are two maps
						DependentBeanMap, key = dep(B), value = LinkedHashSet (A... Rely on the
						DependenciesForBeanMap, key is beanName(A), value is A LinkedHashSet, beanName(A) is dependent on the deP (B) bean
						registerDependentBean(dep, beanName);
						try {
							// Generate the dependent bean first
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}/ / 5,
				// Create the bean according to Scope
				// Create an instance object of the singleton Bean
				if (mbd.isSingleton()) {
					// Using an anonymous inner class, create Bean instance objects and register dependent objects
					sharedInstance = getSingleton(beanName, () -> {
						try {
								return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// If the creation fails, explicitly destroy the given bean from the container
							destroySingleton(beanName);
							throwex; }});// sharedInstance can be a FactoryBean if it is a FactoryBean
					// Then all you really need is the object returned by getObject
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
            / / 6,
				// Create the prototype pattern Bean instance object
				else if (mbd.isPrototype()) {
					Object prototypeInstance = null;
					try {
						/ / will create Bean tags to create the current operation is prototypesCurrentlyInCreation this property
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						/ / create a complete, removed from prototypesCurrentlyInCreation beanName
						afterPrototypeCreation(beanName);
					}
					// prototypeInstance can be a FactoryBean, if it is a FactoryBean,
					// Then all you really need is the object returned by getObject
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				// If the lifecycle scope of the Bean to be created is not Singleton, nor prototype
				// Fetch the life cycle from this.scopes. Get (scopeName); Instantiate the Bean
				// For example, the life cycle of request and session
              / / 7,
				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, () -> {
							/ / will create Bean tags to create the current operation is prototypesCurrentlyInCreation this property
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								/ / create a complete, removed from prototypesCurrentlyInCreation beanNameafterPrototypeCreation(beanName); }});// scopedInstance can be a FactoryBean, if it is a FactoryBean,
						// Then all you really need is the object returned by getObject
						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);
				throwex; }}Copy the code
  • 1. :SpringFirst of all checkbeanNameWhether inprototypesCurrentlyInCreation,prototypesCurrentlyInCreationIs aThreadLocal, stores the prototype that is currently being createdbeanNameThe collection,SpringPrototype not supportedbeanSo one is thrownBeanCurrentlyInCreationExceptionThe exception.
  • 2, : Get the parent container, if the current container’s parent container exists and the current container does not have the specified nameBeanDefinitionTry to get the bean instance from the parent container.
  • 3, : Whether to get the instance for type checking. will beanNamejoinalreadyCreatedIn the Set collection, stores already created or in process of being createdbeanNameAnd callclearMergedBeanDefinitionMethod to delete the merge bean definition for the specified bean and set stale to true. Stale is true before bean merging.
  • 4, : willGernericBeanDefinitionconvertRootBeanDefinition, if specifiedbeanNameA child Bean merges the attributes of its parent. If the current bean has a dependent bean, the dependent bean is recursively instantiated or thrown if it is interdependentBeanCreationExceptionThe exception.
  • 5. IfBeanThe scope of issingleton, creates an instance object of the singleton Bean. Here Spring calls an overloadedgetSingleton(String beanName, ObjectFactory<? > singletonFactory)Method implements the Bean loading.
public Object getSingleton(String beanName, ObjectFactory
        singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			// Get the instance from the singleton pool
			Object singletonObject = this.singletonObjects.get(beanName);

			// If no instance exists, create a singleton bean instance
			if (singletonObject == null) {
				// The current singleton is being destroyed, throwing an exception
				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 + "'");
				}
				/ / is created in the current beanName added to the singletonsCurrentlyInCreation,
				/ / singletonsCurrentlyInCreation is a Set
				// Indicates that these singleton beans are normally created and cannot be created again until they are completed
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// singletonFactory is a lambda expression passed in from the outside
					Call createBean()
					// Create a singleton bean
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throwex; }}catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); }}throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					/ / will be removed from just is creating beanName singletonsCurrentlyInCreation
					afterSingletonCreation(beanName);
				}

				// Add the created singleton bean to the singleton pool singletonObjects
				// and the singleton registeredSingletons
                // Clear level 2 and level 3 caches
				if(newSingleton) { addSingleton(beanName, singletonObject); }}returnsingletonObject; }}Copy the code
  • 6: ifBeanThe scope of isprototype, the prototype pattern Bean instance object is created. Direct callcreateBeanMethod, prototype mode, every timegetBeanCreates a new object instance.
  • 7: If the Bean is not scopedsingletonprototype, fromthis.scopes.get(scopeName)Get the scope and instantiate the Bean.

Type checking

Just look at it.

// Check that the desired type matches the type of the actual bean instance
if(requiredType ! =null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}Copy the code

The data object

// The name of the prototype bean currently being created
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
            new NamedThreadLocal<>("Prototype beans currently in creation");
			
// The bean defines the object with the key beanName
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

// Merge RootBeanDefinition with key beanName
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

// Store beanName that has been created or is being created
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

/ / the singleton pool
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// The singleton factory cache, Bean name to ObjectFactory, this reference information will be removed from the secondary cache once the final object is created (via objectFactory.getobject ())
private finalMap<String, ObjectFactory<? >> singletonFactories =new HashMap<>(16);  

// Store a reference to the original Bean created early in the Bean creation process. Note that this is the original Bean, which is an object created using a factory method or constructor.
// Once the object is finally created, this reference information will be removed from the tertiary cache
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

// The name of the bean currently excluded in the creation check
private final Set<String> inCreationCheckExclusions =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
			
// The name of the bean currently being created, indicating that the bean is being created normally and cannot be created again until it has been created
private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

// Registered singleton beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
Copy the code

The next article will start to read the source code of createBean.

  • If you have any questions or errors in this article, please feel free to comment. If you find this article helpful, please like it and follow it.