Spring Source Analysis (11) Bean loading

Source: Internet
Author: User

Abstract: This article combines the spring source depth analysis to analyze the source code of Spring 5.0.6 version. If there is any description of the error, please correct me.

After the previous analysis, we finally end the parsing of the XML configuration file, the next challenge is to explore the bean load. The function implementation of bean loading is much more complex than that of bean parsing. Again, based on the first example, the function to load a bean is called in spring in the following way:

Myspringbean bean = (myspringbean) beanfactory.getbean ("Myspringbean");

What kind of function does this code implement? Let's take a quick look at how the code in spring is implemented.

@Override PublicObject Getbean (String name)throwsbeansexception {returnDogetbean (Name,NULL,NULL,false);}protected<T> T Dogetbean (FinalString name, @NullableFinalClass<t>Requiredtype, @NullableFinalObject[] args,BooleanTYPECHECKONLY)throwsbeansexception {//extract the corresponding beanname    FinalString Beanname =transformedbeanname (name);    Object Bean; /*** Check if there is a corresponding instance in the cache or in the instance factory * Why is this code first used? * Because of the dependency injection when creating the bean, and in order to avoid cyclic dependencies when creating dependencies, the principle of creating beans in spring is that the objectfactory of the bean creation will be exposed before the bean creation is complete, which will OBJECTF Actory is added to the cache, and once the next bean is created it relies on the last bean to use the objectfactory directly.*/    //eagerly check singleton cache for manually registered singletons. //first try to get from the cache or the objectfactory in SingletonfactoriesObject sharedinstance =Getsingleton (beanname); if(Sharedinstance! =NULL&& args = =NULL) {        if(logger.isdebugenabled ()) {if(Issingletoncurrentlyincreation (beanname)) {Logger.debug ("Returning eagerly cached instance of singleton beans '" + beanname + "' That's not fully initializ Ed Yet-a consequence of a circular reference "); }            Else{logger.debug ("Returning cached instance of singleton beans '" + beanname + "'"); }        }        //returns the corresponding instance, sometimes a situation such as Beanfactory does not return the instance itself directly but returns the instance returned by the specified method .Bean = getobjectforbeaninstance (sharedinstance, name, Beanname,NULL); }    Else {        //Fail If we ' re already creating this bean instance://We ' re assumably within a circular reference.        /*** Only in a single case will try to solve the cyclic dependency, prototype mode case, if there is a property of B in A, B has a attribute, * then when the dependency injection, it will be generated when a is not created, because the creation of B again returned to create a, * Causes cyclic dependence, that is, the following condition Isprototypecurrentlyincreation (beanname) is true*/        if(Isprototypecurrentlyincreation (beanname)) {Throw Newbeancurrentlyincreationexception (beanname); }        //Check If bean definition exists in this factory. //if Beandefinitionmap is not included in all classes that have already been loaded, Beanname attempts to detect from ParentbeanfactoryBeanfactory parentbeanfactory =getparentbeanfactory (); if(Parentbeanfactory! =NULL&&!containsbeandefinition (Beanname)) {            //Not found, check parent.String Nametolookup =originalbeanname (name); //recursive to beanfactory search            if(parentbeanfactoryinstanceofabstractbeanfactory) {                return((abstractbeanfactory) parentbeanfactory). Dogetbean (Nametolookup, Requiredtype, args, Typeche            CKONLY); }            Else if(Args! =NULL) {                //delegation to parent with explicit args.                return(T) Parentbeanfactory.getbean (nametolookup, args); }            Else if(Requiredtype! =NULL) {                //No args-Delegate to standard Getbean method.                returnParentbeanfactory.getbean (Nametolookup, requiredtype); }            Else {                return(T) Parentbeanfactory.getbean (nametolookup); }        }        //If you are not just doing type checking, you are creating a bean, and you are logging        if(!typecheckonly)        {markbeanascreated (beanname); }        Try {            //convert the genericbeandefinition that stores the XML configuration file to Rootbeandefinition,//If you specify Beanname as a child bean, the associated properties of the parent class are merged            FinalRootbeandefinition MBD =getmergedlocalbeandefinition (beanname);            Checkmergedbeandefinition (mbd, beanname, args); //Guarantee Initialization of beans , the current bean, depends on.string[] DependsOn =Mbd.getdependson (); //recursive instantiation of dependent beans if there is dependency            if(DependsOn! =NULL) {                 for(String dep:dependson) {if(Isdependent (Beanname, DEP)) {Throw Newbeancreationexception (Mbd.getresourcedescription (), Beanname,"Circular depends-on Relationship between '" + Beanname + "' and '" + dep + "'"); }                    //Cache Dependent callsRegisterdependentbean (DEP, Beanname); Try{Getbean (DEP); }                    Catch(Nosuchbeandefinitionexception ex) {Throw Newbeancreationexception (Mbd.getresourcedescription (), Beanname,"'" + beanname + "' depends on missing bean '" + dep + "'", ex); }                }            }            //Create Bean instance. //after instantiating a dependent bean, you can instantiate the MBD itself.//creation of the singleton mode            if(Mbd.issingleton ()) {sharedinstance= Getsingleton (Beanname, () {                    Try {                        returnCreatebean (Beanname, mbd, args); }                    Catch(Beansexception ex) {//explicitly remove instance from Singleton Cache:it might has been put there//eagerly by the creation process, to allow for circular reference resolution. //Also Remove any beans this received a temporary reference to the bean.Destroysingleton (beanname); Throwex;                }                }); Bean=getobjectforbeaninstance (sharedinstance, name, Beanname, mbd); }            Else if(Mbd.isprototype ()) {//It's a prototype, create a new instance. //creation of the prototype modeObject prototypeinstance =NULL; Try{beforeprototypecreation (beanname); Prototypeinstance=Createbean (Beanname, mbd, args); }                finally{afterprototypecreation (beanname); } Bean=getobjectforbeaninstance (prototypeinstance, name, Beanname, mbd); }            Else {                //instantiates a bean on the specified scopeString ScopeName =Mbd.getscope (); FinalScope scope = This. Scopes.get (ScopeName); if(Scope = =NULL) {                    Throw NewIllegalStateException ("No scope registered for scope name '" + scopeName + "'"); }                Try{Object scopedinstance= Scope.get (Beanname, (){beforeprototypecreation (beanname); Try {                            returnCreatebean (Beanname, mbd, args); }                        finally{afterprototypecreation (beanname);                    }                    }); Bean=getobjectforbeaninstance (scopedinstance, name, Beanname, mbd); }                Catch(IllegalStateException ex) {Throw Newbeancreationexception (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 singlet On, ex); }            }        }        Catch(Beansexception ex) {cleanupafterbeancreationfailure (beanname); Throwex; }    }    //Check if required type matches the type of the actual bean instance. //Check that the type you want is the actual type of bean    if(Requiredtype! =NULL&&!requiredtype.isinstance (Bean)) {        Try{T Convertedbean=Gettypeconverter (). Convertifnecessary (Bean, requiredtype); if(Convertedbean = =NULL) {                Throw Newbeannotofrequiredtypeexception (name, Requiredtype, Bean.getclass ()); }            returnConvertedbean; }        Catch(Typemismatchexception ex) {if(logger.isdebugenabled ()) {Logger.debug ("Failed to convert Bean" + name + "' to Required type '" +classutils.getqualifiedname (requiredtype)+ "'", ex); }            Throw Newbeannotofrequiredtypeexception (name, Requiredtype, Bean.getclass ()); }    }    return(T) bean;}

It can be seen from the amount of code that the bean's loading has undergone a rather complex process involving a variety of considerations. It is believed that the reader can read the above code carefully, and refer to some code comments, which is a rough understanding of the entire load bean process. The steps involved in the loading process are outlined below.

(1) Convert the corresponding beanname.

Perhaps a lot of people do not understand the conversion of the corresponding beanname means, the parameter passed in name is not beanname it? In fact, the parameters passed in here may be aliases or Factorybean, so a series of parsing will be required, including the following content.

    • Remove the Beanfactory modifier, that is, if Name= "&hello", then the & will be removed first to make the Name= "Hello".
    • Takes the final beanname represented by the specified alias, for example, alias a points to a bean with the name B and returns B if alias a points to alias B, and the alias B to the Bean with the name C returns c.

(2) Try to load the singleton from the cache.

The Singleton is created only once in the same container in spring, and the subsequent fetch of the bean is obtained directly from the singleton cache. Of course, this is just trying to load, first trying to load from the cache, if the load is unsuccessful, try to load from singletonfactories again. Because there is a dependency injection when creating a singleton bean, and in order to avoid circular dependencies when creating dependencies, the principle of spring's creation of beans is that the objectfactory of the bean creation will be exposed before the bean creation is complete. That is, Objectfactory is added to the cache, and once the next bean is created it relies on the last bean to use objectfactory directly.

(3) instantiation of the bean.

If you get the original state of the bean from the cache, you need to instantiate the bean. It is important to emphasize that the cache is only the most primitive bean state, and not necessarily the bean we want to end up with. For example, if we need to process the factory bean, what we get here is actually the initial state of the factory bean, but what we really need is the bean that is returned by the Factory-method method defined in the factory bean. And Getobjectforbeaninstance is the completion of this work, follow-up will be explained in detail.

(4) Dependency checking of prototype mode.

Only in a single case will try to solve the cyclic dependency, prototype mode, if there is a in the properties of B, B has a property, then when the dependency injection, it will be generated when a is not created, because the creation of B again returned to create a, resulting in a cyclic dependency, That is, the situation: Isprototypecurrentlyincreation (Beanname) is true.

(5) Detection parentbeanfactory.

From the code, if the cache does not have data, go directly to the parent factory to load, this is why?

Perhaps the reader ignores a very important condition: parentbeanfactory! = null &&!containsbeandefinition (beanname). Parentbeanfactory if empty, then everything else is a cloud, but!containsbeandefinition (beanname) is more important, It is detected that if the currently loaded XML configuration file does not contain the corresponding configuration of beanname, it is only possible to go to parentbeanfactory to try and then recursively invoke the Getbean method.

(6) Convert the genericbeandefinition that stores the XML configuration file to Rootbeandefinition.

Because the bean information read from the XML configuration file is stored in genericbeandefinition, but all of the bean's subsequent processing is for the rootbeandefinition, so the conversion is needed here, The property of the parent class is merged together with the conversion if the parent bean is not empty.

(7) Look for dependencies.

Because some properties are most likely to be used during the initialization of a bean, and some properties are most likely dynamically configured and are configured to depend on other beans, then it is necessary to load the dependent bean first, so in the load order of sring, initializing a bean First initializes the dependency of the bcan.

(8) The creation of beans for different scopes.

As we all know, there are different scopes in Spring, the default is singleton, but there are other configurations such as prototype, request, and so on. In this step, sring will make different initialization policies based on the different configurations.

(9) Type conversion.

The program has basically ended up here after returning the bean, usually the call parameter of the method Requiredtype is empty, but there might be a case where the returned bean is actually a String, but requiredtype passed in the integer type. Then this step will work, and its function is to convert the returned bean to the type specified by Requiredtype. Of course, String conversion to Integer is the simplest kind of conversion, which provides a variety of converters in Spring, and the user can also extend the converter to meet the requirements.

After the above steps, the bean's load is over, and this time the bean needs to be returned. The most important of these is step (8), the creation of beans for different scopes, you will see the implementation of a variety of common Spring features here.

Spring Source Analysis (11) Bean loading

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.