Basic concepts
Beandefinitiondocumentreader, the function of this class has two, complete beandefinition parsing and registration.
Parsing: is actually the process of parsing ddocument content and adding it to the beandefinition instance.
Registration: Is the process of adding beandefinition to the Beandefinitionholder, which is done to save its information.
Here's an interface definition that defines only one method that is responsible for parsing and registering:
public interface BeanDefinitionDocumentReader { void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)throws BeanDefinitionStoreException;}
Then look at its inheritance, with only one implementation class by default:
SOURCE Analysis
Next, look at the Registerbeandefinitions method in the Defaultbeandefinitiondocumentreader class.
First look at the parameters of the method:
Document: Refers to Spring's profile information, which is obtained by Beandefinitionreader parsing the Resrouce instance.
Xmlreadercontext: Mainly includes Beandefinitionreader and resrouce.
Take a look at its specific process:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 日志输出... // 取得根元素,即 XML 文件中的 <beans> 标签 Element root = doc.getDocumentElement(); // 关键 -> 继续 Document 的解析 doRegisterBeanDefinitions(root);}
With regard to doregisterbeandefinitions, the main functions of this method are:
Creates a Beandefinitionparserdelegate object that converts the contents of the Document into an beandefinition instance, the parsing process mentioned above, Beandefinitiondocumentreader It does not have the function but is given to the class to complete.
Gets the property content of the profile in the beans tag, which is used primarily for environment switching. For example, during the development process, there may be different data sources between the test environment and the formal environment. If you want to achieve a rapid change in the environment, you can use profile to configure. Concrete implementation here is not explored.
ProtectedvoidDoregisterbeandefinitions (Element root) {Create delegate object Beandefinitionparserdelegate parent =This.delegate;This.delegate = CreateDelegate (Getreadercontext (), root, parent);Validates the namespace of the XML file, that is, whether it contains xmlns= "Http://www.springframework.org/schema/beans"if (this.delegate.isDefaultNamespace (root)) { //parse profile String Profilespec = Root.getattribute (profile_ ATTRIBUTE); if (Stringutils.hastext (Profilespec)) {string[] specifiedprofiles = Stringutils.tokenizetostringarray ( Profilespec, beandefinitionparserdelegate.multi_value_attribute_delimiters); if (!getreadercontext (). Getenvironment (). Acceptsprofiles (Specifiedprofiles)) { return;}}} //Null method Preprocessxml (root); //Key--Start parsing Bean definition parsebeandefinitions (root, this.delegate); //Null method Postprocessxml (root); this.delegate = parent;}
The following starts by traversing all the child nodes that get the beans element.
ProtectedvoidParsebeandefinitions (Element root, beandefinitionparserdelegate delegate) {Validating XML file namespacesif (Delegate.isdefaultnamespace (root)) {//get <beans> All child nodes of NodeList nl = Root.getchildnodes (); //traverse <beans> Sub-node for (int I = 0; i < nl.getlength (); i++) {Node node = Nl.item (i); //determine if the node is Element type if (node if (Delegate.isdefaultnamespace (ele)) {//key-< resolution Beans> parsedefaultelement (Ele, delegate) of the child nodes; }else {//parse the custom element, temporarily do not explore delegate.parsecustomelement (ele);}}} else {delegate.parsecustomelement (root);}}
After the child node is taken, the child nodes of the beans tag are parsed, and the common tags are import,alias,bean,beans and so on.
PrivatevoidParsedefaultelement (Element ele, beandefinitionparserdelegate delegate) {//Processing <import> labeling, merging resources and resolving if (Delegate.nodenameequals (Ele, import_element)) {Importbeandefinitionr Esource (ele); } //processing <alias> label else if (delegate.nodenameequals (Ele, alias_element)) {processaliasregistration ( Ele); } //Key---process <bean> label else if (delegate.nodenameequals (Ele, bean_element)) {processbeandefinition ( Ele, delegate); } //processing <beans> tags, go back to the place where you started parsing the document, else if (delegate.nodenameequals (Ele, nested_beans_element)) { c11>//recurse doregisterbeandefinitions (ele); }}
The key here is to explore the bean parsing process:
The specific parsing of the bean tag mentioned above is given to the Beandefinitionparserdelegate class to complete.
Use Beandefinitionregistry to complete the registration process after parsing has been taken beandefinition (added to the Beandefinitionholder) object.
ProtectedvoidProcessbeandefinition (Element ele, beandefinitionparserdelegate delegate) {//key->① to the delegate class delegate to complete the parsing process, and return Beandefinitionholder object This object stores the basic information of beandefinition beandefinitionholder Bdholder = delegate.parsebeandefinitionelement (ele); //to the delegate class delegate to complete the decoration process, here temporarily do not explore if (bdholder! = null) {Bdholder = delegate.decoratebeandefinitionifrequired (Ele, Bdholder); try {//key->② register the last decorative instance Beandefinitionreaderutils.registerbeandefinition (Bdholder, Getreadercontext (). GetRegistry ()); }catch (Beandefinitionstoreexception ex) {//error Output ...} //Send registration event. Getreadercontext (). firecomponentregistered (new beancomponentdefinition (BdHolder));}}
Observing the above code, it is found that the main function of Defaultbeandefinitiondocumentreader is to parse the document, get the label content defined in the configuration file (this is referred to as XML), and the process of parsing the label is given The Beandefinitionparserdelegate class is completed, and the registration process is given to the Beandefinitionregistry interface to complete.
1.BeanDefinition parsing
The parsing methods for bean labels in Defaultbeandefinitiondocumentreader are as follows:
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
Here's a look at the Parsebeandefinitionelement method of Beandefinitionparserdelegate.
Public BeandefinitionholderParsebeandefinitionelement (Element ele) {Return Parsebeandefinitionelement (Ele,NULL);}Public BeandefinitionholderParsebeandefinitionelement (Element ele, beandefinition Containingbean) {Gets the id attribute of the <bean> tag String id = ele.getattribute (id_attribute);Get the Name property of the <bean> tag String nameattr = Ele.getattribute (Name_attribute);Create List to store method Alsas (alias) collection list<string> aliases =New Arraylist<string> ();if (Stringutils.haslength (nameattr)) {Divide Namearr by (,) or (;) string[] Namearr = Stringutils.tokenizetostringarray (nameattr, Multi_value_attribute_ delimiters);Add the Alias Collection Aliases.addall (Arrays.aslist (Namearr)); }Determines whether the ID is empty, and if empty, takes the first element of the alias collection as the ID and removes the String beanname = ID from the alias collection;if (! Stringutils.hastext (beanname) &&!aliases.isempty ()) {beanname = Aliases.remove (0);Log output ...}Check if ID (identity) and alias (name) are uniqueif (Containingbean = =NULL) {checknameuniqueness (beanname, aliases, ele);}Key---parse <bean> tag's class attribute and related attribute tag and add it to beandefinition return abstractbeandefinition beandefinition = Parsebe Andefinitionelement (Ele, Beanname, Containingbean);if (beandefinition! =NULL) {Determine if Beanname (ID) existsif (! Stringutils.hastext (Beanname)) {try {if (Containingbean! =NULL) {Beanname = Beandefinitionreaderutils.generatebeanname (Beandefinition,This.readerContext.getRegistry (),true); }else {Automatically generated by Spring Beanname (id) beanname =This.readerContext.generateBeanName (beandefinition);Get the full class name of the bean available as String beanclassname = Beandefinition.getbeanclassname ();Add Beanname into Alais collectionif (beanclassname! = null && beanname.startswith ( Beanclassname) && beanname.length () > Beanclassname.length () &&! this.readercontext.getregistry (). Isbeannameinuse (Beanclassname)) {Aliases.add (beanclassname);} } //log output ...} catch (Exception ex) {error (Ex.getmessage (), ele); return null;} //aliases set array string[] Aliasesarray = Stringutils.tostringarray (aliases); //Key--Returns a Beandefinitionholder instance for storing information return new beandefinitionholder (Beandefinition, Beanname, Aliasesarray); } return null;}
Then look at parsing the class attribute of the bean tag and the associated attribute tag and adding it to the beandefinition return process:
Public abstractbeandefinitionParsebeandefinitionelement (Element ele, String beanname, beandefinition Containingbean) {Into the stack, add a new beanentry to the ParsestateThis.parseState.push (New Beanentry (Beanname));Get the Class property of the <bean> tag String className =Nullif (Ele.hasattribute (Class_attribute)) {className = Ele.getattribute (Class_attribute). Trim ();try {Gets the Parent property of the <bean> tag, String parent =Nullif (Ele.hasattribute (Parent_attribute)) {PARENT = Ele.getattribute (Parent_attribute);}Create a beandefinition abstractbeandefinition BD = Createbeandefinition (className, parent) based on the attribute value of class,parent;Get the additional attributes of the <bean> tag and add the beandefinition. Such as:ScopeLazy-initAutowirePrimary, Autowire-candidateDepends-on, Dependency-checkInit-method, Destroy-methodFactory-method, Factory-bean parsebeandefinitionattributes (Ele, Beanname, Containingbean, BD); Bd.setdescription (Domutils.getchildelementvaluebytagname (Ele, description_element));Parsing <mate> Labeling Parsemetaelements (Ele, BD);Parsing <lookup-method> Labeling Parselookupoverridesubelements (Ele, Bd.getmethodoverrides ());Parsing <replaced-method> Labeling Parsereplacedmethodsubelements (Ele, Bd.getmethodoverrides ());Parsing <constructor-arg> Labeling Parseconstructorargelements (Ele, BD);//parsing <property> labeling Parsepropertyelements (Ele, BD); //parsing <qualifier> labeling Parsequalifierelements (Ele, BD); Bd.setresource (this.readerContext.getResource ()) ; Bd.setsource (Extractsource (ele)); return BD;} catch (ClassNotFoundException ex) { //error Output ...} catch (Noclassdeffounderror err) { //error Output ...} catch (Throwable ex) { //error Output ...} finally { //out stack operation This.parseState.pop ();} return null;}
2.Beandefinition Registration
The registration method for bean labels in Defaultbeandefinitiondocumentreader is as follows:
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
Here's a look at Beandefinitionreaderutils's Registerbeandefinition method. The main function of this method is to invoke the Registrar to complete the registration process.
public static void registerbeandefinition (Beandefinitionholder definitionholder, Beandefinitionregistry registry) throws Beandefinitionstoreexception { //Gets the identity of the Beandefinition instance String Beanna me = Definitionholder.getbeanname (); //Key---call the Registrar to implement the registration process Registry.registerbeandefinition (Beanname, Definitionholder.getbeandefinition ()); //Get all aliases for beandefinition instances string[] aliases = definitionholder.getaliases (); if (aliases! = null) {for (String alias:aliases) { //Aliasmap add alias to Registrar's procedure Registry.registeral IAS (Beanname, alias); } }}
07.Spring Bean parsing-Beandefinitiondocumentreader