Spring source code (5)-get Bean-getBean

Spring source code (5)-get Bean-getBean

We have read part of it in the previous article

getBean
The source code of the, if the instance is obtained from the singleton pool, the instance is judged whether it is
FactoryBean
,in the case of
FactoryBean
, Then what you really need to get is
getObject
The object returned by the method. In this section, continue to look down. If no instance is obtained from the singleton pool, what will Spring do?

The singleton pool did not get the bean

//The above code is omitted--- //The singleton pool does not get the Bean else { //Whether the specified prototype bean is being created, if it is, an exception will be thrown //Spring does not support the circular dependency of prototype beans //Currently being created The prototype Bean will be placed in the ThreadLocal prototypesCurrentlyInCreation //, if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //2, //Get the 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)) { //The user-specified bean name is parsed into a canonical name and spliced & Symbol 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 parameters, delegated to the parent to search 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.//No args -> delegate to the parent to search according to the specified name and type return parentBeanFactory.getBean(nameToLookup, requiredType); } else { //Delegate the parent to search based on the specified name. return (T) parentBeanFactory.getBean(nameToLookup); } } //3, //Mark the specified bean as created (or about to be created). //typeCheckOnly passed in the upper layer is false //You can go to see the Spring source code (2)-XML file reading-BeanDefinitionReader This article has 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 properties of the parent class will be merged at the same time final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); //Check the given merged bean definition checkMergedBeanDefinition(mbd, beanName, args); //Ensure that the bean that the current bean depends on has been initialized. First load the bean specified by DependsOn //xml writing //<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 //@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) { //Determine if beanName(A) is also dependent on dep(B), if so, it is dependent on each other, throw an exception if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription( ), beanName, "Circular depends-on relationship between'" + beanName + "'and'" + dep + "'" ); } //There are two maps //1. dependentBeanMap, key is dep(B), value is a LinkedHashSet, indicating which beans(A...) depend on dep(B) //2. dependenciesForBeanMap, key is beanName (A), value is a LinkedHashSet, indicating which dep(B) beans the beanName(A) depends on registerDependentBean(dep, beanName); try { //first to generate dependent beans getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "'depends on missing bean'" + dep + "'" , ex); } } } //5, //Create bean according to Scope //Create instance object of singleton mode Bean if (mbd.isSingleton()) { //Use an anonymous inner class to create Bean instance object 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); 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 mode Bean instance object else if (mbd.isPrototype()) { Object prototypeInstance = null ; try { //Mark the currently created Bean as the property that is being created, which is prototypesCurrentlyInCreation beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { //Creation is complete, 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 scope of the Bean to be created is not singleton, nor prototype //get the life cycle from this.scopes.get(scopeName); instantiate the Bean //such as: request, session, etc. life cycle //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 the property that is being created, that is, prototypesCurrentlyInCreation beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { //Creation is complete, remove beanName from prototypesCurrentlyInCreation afterPrototypeCreation(beanName); } }); //scopedInstance 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; } } Copy code
  • 1,:
    Spring
    First check
    beanName
    Is it in
    prototypesCurrentlyInCreation
    in,
    prototypesCurrentlyInCreation
    Is an
    ThreadLocal
    , Which stores the prototype currently being created
    beanName
    set,
    Spring
    Prototype is not supported
    bean
    Cyclic dependency, so it will throw a
    BeanCurrentlyInCreationException
    abnormal.
  • 2.: Get the parent container, if the parent container of the current container exists and the specified name does not exist in the current container
    BeanDefinition
    , Try to get the bean instance in the parent container.
  • 3.: Whether to obtain an instance for type checking. will
    beanName
    Join
    alreadyCreated
    In the Set collection, store the ones that have been created or are being created
    beanName
    And call
    clearMergedBeanDefinition
    Method, delete the merged bean definition of the specified bean, and set stale to true. Only when stale is true will the bean merge be performed.
  • 4.: Change
    GernericBeanDefinition
    Convert to
    RootBeanDefinition
    , If you specify
    beanName
    If it is 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 are instantiated recursively, and if they are dependent on each other, throw
    BeanCreationException
    abnormal.
  • 5.: If
    Bean
    The scope is
    singleton
    , An instance object of a singleton bean is created. Here Spring calls an overloaded
    getSingleton(String beanName, ObjectFactory<?> singletonFactory)
    The method implements the loading of the Bean.
public Object getSingleton (String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null" ); synchronized ( this .singletonObjects) { //Go to the singleton pool to obtain an instance Object singletonObject = this .singletonObjects.get(beanName); //If there is no instance, create a singleton bean instance if (singletonObject == null ) { //The current singleton is being destroyed and 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 beans are being created normally, and cannot be created repeatedly when they are not created. beforeSingletonCreation(beanName); boolean newSingleton = false ; boolean recordSuppressedExceptions = ( this .suppressedExceptions == null ); if (recordSuppressedExceptions) { this .suppressedExceptions = new LinkedHashSet<>(); } try { //singletonFactory is the lambda expression passed in from the outside, and executing the lambda expression //is to 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 ) { 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 just being created from singletonsCurrentlyInCreation afterSingletonCreation(beanName); } //Add the created singleton bean to the singleton pool singletonObjects //and the singleton registry registeredSingletons //and clear the secondary and tertiary cache if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } } Copy code
  • 6: if
    Bean
    The scope is
    prototype
    , Then create the prototype mode Bean instance object. Direct call
    createBean
    Method, in prototype mode, every time
    getBean
    New object instances will be created.
  • 7: If the scope of the Bean is not
    singleton
    with
    prototype
    , Then from
    this.scopes.get(scopeName)
    Get the scope and instantiate the Bean.

Type check

Just take a look.

//Check if 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()); } } Copy code

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 ); //The merged RootBeanDefinition, the key is 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 )); //Singleton pool private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>( 256 ); //Singleton factory cache, Bean name to ObjectFactory, once the final object is created (via objectFactory.getObject()), this reference information will be deleted from the secondary cache private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap <>( 16 ); //Used to store a reference to the original bean created in the early stage of creating the Bean. Note that this is the original bean, that is, the object created using the factory method or the construction method. //Once the object is finally created, this reference information will be deleted. Level cache private final Map<String, Object> earlySingletonObjects = new HashMap<>( 16 ); //The name of the bean currently excluded in the creation check is private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap( new ConcurrentHashMap<>( 16 )); //The name of the bean that is currently being created means that these beans are being created normally, and the private final Set<String> singletonsCurrentlyInCreation = cannot be created repeatedly when they are not created . Collections.newSetFromMap( new ConcurrentHashMap<>( 16 )); //registered singleton beanName private final Set<String> registeredSingletons = new LinkedHashSet<>( 256 ); Copy code

Start of the next part

createBean
Reading the source code, I am a little excited to think about it.

  • If you have any questions about this article or there are errors in this article, please comment and leave a message to point out. If you think this article is helpful to you, please like and pay attention.