In the previous article, we have read some of the source code of getBean. If we get an instance from the singleton pool, we will judge whether it is a FactoryBean. If it is a FactoryBean, what we really need to get is the object returned by the getObject method. This section continues. What will Spring do if you don't get an instance from the singleton pool?
The singleton pool did not get a Bean
//The above code is omitted--- //The singleton pool did not get a Bean else { // Whether the specified prototype bean is being created. If so, an exception will be thrown // Spring does not support circular dependency of prototype bean s // The prototype beans currently being created will be placed in the ThreadLocal of prototypes currentyincreation //1, if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //2, //Get parent BeanFactory BeanFactory parentBeanFactory = getParentBeanFactory(); //The parent container of the current container exists and the BeanDefinition with the specified name does not exist in the current container, if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { //Resolve the bean name specified by the user to the canonical name and splice the & symbol String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { // recursive lookup return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. //If there are parameters, delegate to the parent to find them according to the specified name and explicit parameters return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. //There is no parameter - > delegate to the parent to find according to the specified name and type return parentBeanFactory.getBean(nameToLookup, requiredType); } else { // The delegate parent finds the by the specified name return (T) parentBeanFactory.getBean(nameToLookup); } } //3, // Mark the specified bean as created (or about to be created). // typeCheckOnly is passed in as false // You can go to the Spring source code (II) - reading XML files - BeanDefinitionReader. There is a method hasBeanCreationStarted() // The markBeanAsCreated method is to add data to the alreadyCreated Set if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { //4, // Get the merged RootBeanDefinition // If the specified BeanName is a child Bean, the related attributes of the parent class will be merged at the same time 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 has been initialized. Load the bean specified by DependsOn first //xml writing method //<bean class="com.gongj.bean.Person" id="person" depends-on="user"></bean> //<bean class="com.gongj.bean.User" id="user" depends-on="person"></bean> //Annotation writing method //@DependsOn("user") //Get the names of all dependent beans of the current Bean. For example, the current beanName is a, and a depends on B String[] dependsOn = mbd.getDependsOn(); // dependsOn is B if (dependsOn != null) { for (String dep : dependsOn) { // Judge whether beanName(A) is also dependent on dep(B). If yes, it is interdependent. Throw an exception if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // Exist in two map s // 1. dependentBeanMap, the key is dep(B), and the value is a LinkedHashSet, indicating which beans (a...) dep(B) is used by Rely on // 2. dependenciesForBeanMap, key is beanName(A), and value is a LinkedHashSet, indicating which dep (b) beans beanName(A) depends on 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 bean s according to Scope //Create an instance object of a singleton pattern Bean if (mbd.isSingleton()) { //Use an anonymous inner class to create a Bean instance object and register the dependent object sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { //If the creation fails, the given bean is explicitly destroyed from the container destroySingleton(beanName); throw ex; } }); // sharedInstance may be a FactoryBean. If it is a FactoryBean // Then what you really need to get is the object returned by the getObject method bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //6, //Create prototype pattern Bean instance object else if (mbd.isPrototype()) { Object prototypeInstance = null; try { // Mark the currently created Bean as being operated during creation, that is, the property of prototypesCurrentlyInCreation beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { // After creation, remove beanName from prototypesCurrentlyInCreation afterPrototypeCreation(beanName); } // prototypeInstance may be a FactoryBean. If it is a FactoryBean, // Then what you really need to get is the object returned by the getObject method bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } //If the life cycle range of the Bean to be created is not a singleton or prototype //From this scopes. Get (scopename) to get the life cycle; Instantiate Bean //Such as: request, session and other life cycles //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, () -> { // Mark the currently created Bean as being operated during creation, that is, the property of prototypesCurrentlyInCreation beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { // After creation, remove beanName from prototypesCurrentlyInCreation afterPrototypeCreation(beanName); } }); // Scopeinstance may be a FactoryBean. If it is a FactoryBean, // Then what you really need to get is the object returned by the getObject method 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; } }
- 1. : spring first checks whether the beanName is in the prototypesCurrentlyInCreation. prototypesCurrentlyInCreation is a ThreadLocal that stores the collection of prototype beannames being created. Spring does not support circular dependency of prototype beans, so it will throw a beancurrentyincreationexception.
- 2. : get the parent container. If the parent container of the current container exists and the BeanDefinition with the specified name does not exist in the current container, try to get the bean instance from the parent container.
- 3. : whether to get an instance for type checking. Add the beanName to the alreadyCreated Set set, store the beanName that has been created or is being created, call the clearMergedBeanDefinition method, delete the merged bean definition of the specified bean, and Set the stale to true. Bean merging will be performed only when stale is true.
- 4. : convert GernericBeanDefinition to RootBeanDefinition. If beanName is specified as a child bean, the related attributes of the parent class will be merged at the same time. If the current bean has dependent beans, the dependent beans will be instantiated recursively. If they are interdependent, a BeanCreationException will be thrown.
- 5. : if the scope of the Bean is singleton, the instance object of the singleton Bean is created. Here, Spring calls an overloaded getsingleton (string beanname, objectfactory <? > singletonfactory) method to load the Bean.
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { //Get instances from the singleton pool Object singletonObject = this.singletonObjects.get(beanName); // If no instance exists, a singleton bean instance is created if (singletonObject == null) { // The current singleton is being destroyed. An exception is thrown 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 + "'"); } // Add the beanName currently being created to singletonsCurrentlyInCreation, // singletonsCurrentlyInCreation is a Set //Indicates that these singleton bean s are being created normally and cannot be created repeatedly before they are created 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. Execute the lambda expression //Is to call createBean() // Create 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) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // Remove the beanName you just created from singletonsCurrentlyInCreation afterSingletonCreation(beanName); } // Add the created singleton bean to singletonObjects of singleton pool //And singleton registry registeredsinglets //And clear the L2 and L3 caches if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
- 6: If the scope of the Bean is prototype, a prototype pattern Bean instance object is created. Directly call the createBean method. In the prototype mode, each getBean will create a new object instance.
- 7: If the scope of the Bean is not singleton or prototype, start from this scopes. Get (scopename) gets the scope and instantiates the Bean.
Type check
Just have a look.
//Check whether the required 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 new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } }
data object
//The name of the prototype bean currently being created private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation"); //bean definition object, key is beanName private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); //Merged RootBeanDefinition, key is beanName private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); //Store the beanName that has been created or is being created private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); //Single case pool private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //The cache of the singleton factory. The Bean name is transferred to ObjectFactory. Once the final object is created (through objectFactory.getObject()), this reference information will delete the secondary cache private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); //It is used to store a reference to the original bean created early in the creation of the bean. Note that this is the original bean, that is, the object created using the factory method or construction method, //Once the object is finally created, this reference information will delete the L3 cache private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); //The name of the bean currently excluded from the creation check private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); //The name of the beans currently being created indicates that these beans are being created normally and cannot be created repeatedly before they are created private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // Registered singleton beanName private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
The next chapter starts to read the source code of createBean. I'm a little excited to think about it.
- If you have any questions or mistakes about this article, please comment and point out. If you think this article is helpful to you, you are welcome to praise and pay attention to it.