Spring source Analysis (ii) Spring default label parsing and registration implementation

Source: Internet
Author: User
Tags aliases assert file url

When using spring, I also often use the bean tags, beans tags, import tags, AOP tags, and so on.

The following is a brief introduction to spring's default self-tagged parsing process.


Validation mode (dtd&xsd)The DTD is basically obsolete, and now spring's validation mode is basically using an XSD file as the validation mode of the XML document, and the XSD file can be used to check whether the XML conforms to the specification and is valid. When validating an XML document using an XSD file, in addition to the namespace (xmlns= "Http://www.springframework.org/schema/beans") You must also specify the storage location of the XSD document that corresponds to that namespace. Use the SchemaLocation property to specify the storage location of the XSD document that corresponds to the namespace, which consists of two parts, a URI for the namespace, and the XSD file location or URL address identified by the namespace (xsi:schemalocation= "
Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd ").
namespace URIWhen we use the spring tag, for example when using an AOP tag, where does this AOP tag parse, for example, as shown in the following example:
<?xml version= "1.0" encoding= "UTF-8"? ><beans xmlns= "Http://www.springframework.org/schema/beans" xmlns: Xsi= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:aop= "HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP"  xsi: schemalocation= "        Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/ Spring-beans-3.2.xsd        HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP http://www.springframework.org/schema/aop/ Spring-aop-3.1.xsd  ">         <aop:aspectj-autoproxy/>      <bean name=" Purchaseservice "   class=" Net.itaem.aop.PurchaseService "/>    <bean name=" PurchaseService2 "   class=" Net.itaem.aop.fPurchaseService2 "/>    <bean class=" Net.itaem.aop.LogAspect "/>    </beans>
Where schemalocation contains HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP this address, we can find here we can see that it corresponds to the path of a class, Is Aopnamespacehandler, which represents the implementation of AOP is implemented by this processor.
XSD file locationWe can see the HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP behind the xsi:schemalocation, and then Http://www.springframework.org/schema. /aop/spring-aop-3.2.xsd, this XSD file represents the definition of an AOP tag and the parsing validation specification is defined here. So is not going to this URL http://www.springframework.org/schema/aop/spring-aop-3.2.xsd download it, let us first look at the following:


From which you can see http://www.springframework.org/schema/aop/ Spring-aop-3.2.xsd corresponds to a path, in this path we can find the corresponding XSD file, so, in parsing the label, spring will be more schemas file under the corresponding path to find this check file, if it is not found, it will go back to the Internet to download and then perform the check.

Determining the parsing pattern of XML
The spring configuration file has been written, and when spring starts, how does it determine what kind of XML validation pattern spring is using, whether it's DTD or XSD, let's start with the timing diagram to see how spring is implementing the validation pattern

Figure 1
Around so many methods, we finally see the acquisition of XML validation mode, it is not very painful, to tell the truth, if I did not draw a time series diagram I do not know this is so far. Well, let's take a look at its core implementation code.
protected int Getvalidationmodeforresource (Resource Resource) {int validationmodetouse = Getvalidationmode (); <span Style= "White-space:pre" ></span>//if the authentication mode is manually specified, use the manually specified authentication mode if (validationmodetouse! = Validation_auto) { return validationmodetouse;} <span style= "White-space:pre" ></span>//if not specified, then automatic verification mode int detectedmode = Detectvalidationmode ( Resource); if (detectedmode! = Validation_auto) {return detectedmode;} HMM, we didn ' t get a clear indication ... Let ' s assume xsd,//since apparently no DTD declaration have been found up until//detection stopped (before finding the Do Cument ' s root tag). return validation_xsd;}
In general, we are not manually to specify the spring validation mode, so it is usually spring automatically detects the validation mode of XML, then through what detection, how to implement it, Detectvalidationmode method is how to judge, in fact, the judgment is very simple, is to determine whether the definition of the XML file at the beginning contains the document type definition (DOCTYPE), and if it is included, then it is the DTD's document validation pattern, if not included, is the XSD validation mode.

Loading an XML documentAfter determining the parsing mode of the document, the following calls the Loaddocument method to load the XML document. For XML document loading spring uses the Javax.xml.parsers.DocumentBuilderFactory documentbuilder to parse InputSource, returning the Document object.So how do you get the validation files when parsing? In front of the article said that if there is a local authentication file and then get the authentication file locally, if there is no local authentication file to download the verification file online, then how this is achieved?In fact, the key is to entityresolver this class. What is Entityresolver, the official explanation: if a SAX application needs to implement custom processing of an external corpse, you must implement this interface and register an instance with the Sax drive using the Setentityresolver method. That is, to parse a xmlsax first read the declaration of the XML document, according to the declaration to find the corresponding DTD or XSD definition, and then based on the DTD or XSD to verify the document.In spring with delegatingentityresolver implementation of the Entityresolver class, and at the time of parsing according to the parse file URL to get to the local to find the corresponding authentication file, DTD file is in the current path down to find, XSD file unification is from the Meta-inf/spring.schemas file to find the corresponding copy of the verification file.

Parse and register beandefinitionsLet's continue with the execution of the Doloadbeandefinitions method and take a look at the timing diagram of the parse registration beandefinitions
Figure 2
1) Spring has 4 different default tags, namely, Import,alias,bean,beans, the resolution of the four kinds of labels is done by the Parsedefaultelement method. 2) Custom tags, like AOP tags, are done by the Parsecustomelement method.

Default Label resolutionLet's take a look at how spring parses the default tag, first look at the contents of the Parsedefaultelement method:
private void Parsedefaultelement (Element ele, beandefinitionparserdelegate delegate) {//resolves the import label if ( Delegate.nodenameequals (Ele, import_element)) {Importbeandefinitionresource (ele);} Parsing of the ALIAS tag else if (Delegate.nodenameequals (Ele, alias_element)) {processaliasregistration (ele);} Parsing of the BEAN label else if (Delegate.nodenameequals (Ele, bean_element)) {processbeandefinition (ele, delegate);} Parsing of BEANS tags else if (delegate.nodenameequals (Ele, nested_beans_element)) {//Recursedoregisterbeandefinitions (Ele) ;}}

From above you can see that the big Parsedefaultelement method contains the parse entry for the different default tags in spring 4, the parsing of these 4 kinds of tags is similar, but the most complex of them should be the bean label, because he has the most attributes, the logic is more complex, Let's look at how spring parses the default label through the parsing process of the bean tag. First, the Processbeandefinition method of the Defaultbeandefinitiondocumentreader class:
/** * Process The given bean element, parsing the bean definition * and registering it with the registry. */protected void Processbeandefinition (Element ele, beandefinitionparserdelegate delegate) {Beandefinitionholder Bdholder = Delegate.parsebeandefinitionelement (ele); if (bdholder! = null) {Bdholder = Delegate.decoratebeandefinitionifrequired (Ele, bdholder); try {//Register the final decorated instance. Beandefinitionreaderutils.registerbeandefinition (Bdholder, Getreadercontext (). GetRegistry ());} catch (Beandefinitionstoreexception ex) {Getreadercontext (). Error ("Failed to register bean definition with name '" +bdhol Der.getbeanname () + "'", Ele, ex);} Send registration Event.getreadercontext (). firecomponentregistered (New Beancomponentdefinition (BdHolder));}} 
1) First, the Parsebeandefinitionelement method of the Beandefinitionparserdelegate class is delegated to parse the element, returning an example Bdholder of the Beandefinitionholder type, After this method, the Bdholder example already contains the individual properties that are configured in our configuration file, such as class, Name, ID, alias, and so on. 2) When the returned Bdholder is not empty, if there is a custom attribute under the child node that has the default label, you also need to parse the custom label again, that is, call decoratebeandefinitionifrequired Method 3) After parsing is complete, It is necessary to register the parsed Bdholder, and the registration operation is delegated to the Beandefinitionreaderutils Registerbeandefinition method. 4) Finally a response event is sent, notifying the relevant listener that the bean has been loaded and completed.

Let me take a look at the implementation of the Parsebeandefinitionelement method:
/** * Parses the supplied {@code <bean>} element. May return {@code null} * If there were errors during parse. Errors is reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */public beandefinitionholder parsebeandefinitionelement (Element ele, beandefinition containingbean) {//get id Attribute id = Ele.getattribute (Id_attribute);//Gets the Name property string nameattr = Ele.getattribute (Name_attribute);//Split Name property list< string> aliases = new arraylist<string> (); if (Stringutils.haslength (nameattr)) {string[] Namearr = Stringutils.tokenizetostringarray (nameattr, multi_value_attribute_delimiters); Aliases.addall (Arrays.asList ( Namearr));} String beanname = id;if (! Stringutils.hastext (beanname) &&!aliases.isempty ()) {beanname = Aliases.remove (0); if (logger.isdebugenabled ()) {Logger.debug ("No XML ' id ' specified-using '" + beanname + "' as Bean name and" + aliases + "as aliases");}} if (Containingbean = = null) {checknameuniqueness (beanname, aliases, ele);} Parsing bThe attributes and elements of EAN are divided into geneicbeandefinition (Geneicbeandefinition is the Abstractbeandefinition implementation Class) Abstractbeandefinition Beandefinition = Parsebeandefinitionelement (Ele, Beanname, Containingbean); if (beandefinition! = null) {if (! Stringutils.hastext (Beanname)) {//If beanname is not present, the default rule is used to create beannametry {if (Containingbean! = null) {Beanname = Beandefinitionreaderutils.generatebeanname (Beandefinition, This.readerContext.getRegistry (), true);} else {beanname = This.readerContext.generateBeanName (beandefinition);//Register an alias for the plain Bean class name, I F still possible,//if the generator returned the class name plus a suffix.//this was expected for Spring 1.2/2.0 backward s compatibility. String beanclassname = Beandefinition.getbeanclassname (); if (beanclassname! = null &&beanname.startswith ( Beanclassname) && beanname.length () > Beanclassname.length () &&!this.readercontext.getregistry () . Isbeannameinuse (Beanclassname)) {Aliases.add (beanclassname);}} if (logger.isdebugenablEd ()) {Logger.debug ("Neither XML ' id ' nor ' name ' specified-" + "using generated bean name [" + Beanname + "]");}} catch (Exception ex) {error (Ex.getmessage (), ele); return null;}} string[] Aliasesarray = Stringutils.tostringarray (aliases); return new Beandefinitionholder (Beandefinition, BeanName, Aliasesarray);} return null;}

The core logic of parsing is implemented by the Parsebeandefinitionelement method, so let's see what the Parsebeandefinitionelement method does for us. 1) Extract the ID and name attribute in the element 2) to further parse all other attributes in the bean, which contain scope, singleton, abstract, Lazy-init, Autowire, Dependency-check, Depends-on, Autowire-candidate, Primary, Init-method, Destroy-method, Factory-method, Factory-bean. And parse all the elements under the bean, including: Meta, Lookup-method, Replace-method, Constructor-arg, property, qualifier. After parsing completion of these attributes and elements (many elements and attributes, so this is a huge amount of work), uniformly encapsulated into an instance of the Geneicbeandefinition type. 3) If you detect that the bean does not have a specified beanname, then use the default rule to generate a beanname for the bean. 4) encapsulate the acquired information into the Beandeinitionholder.
Resolution of custom labelsAbout the custom label parsing process, my blog also has introduced, here does not repeat the introduction, want to review a friend can go to see, Spring Source Analysis (iv) Custom label parsing process.

Register BeandefinitionLet's go back to the Processbeandefinition method and find Beandefinition's method of registering Beandefinitionreaderutils.registerbeandefinition (BdHolder, Getreadercontext (). GetRegistry ()); Let's take a look at the detailed implementation inside:
/** * Register The given bean definition with the given Bean factory. * @param definitionholder The bean definition including name and aliases * @param registry The Bean factory to register WI TH * @throws beandefinitionstoreexception if registration failed */public static void Registerbeandefinition ( Beandefinitionholder Definitionholder, Beandefinitionregistry registry) throws Beandefinitionstoreexception {// Register Bean definition under primary name. String beanname = Definitionholder.getbeanname (); Registry.registerbeandefinition (Beanname, Definitionholder.getbeandefinition ());//Register aliases for Beans name, if any. string[] aliases = definitionholder.getaliases (), if (aliases! = null) {for (String aliase:aliases) {Registry.registerali As (Beanname, aliase);}}}

As can be seen above, after the completion of the beandefinition will be registered to beandefinitionregistry inside, wherein the registration of Beandefinition is divided into two parts, one is through beanname registration, One is registered by the alias Aliase.
Register through Beanname beandefinition through Beanname register beandefinition What does spring really do, let's take a look at:
---------------------------------------------------------------------//implementation of Beandefinitionregistry interface//---------------------------------------------------------------------Public void Registerbeandefinition (String beanname, Beandefinition beandefinition) throws Beandefinitionstoreexception { Assert.hastext (Beanname, "Bean name must not be empty"); Assert.notnull (beandefinition, "beandefinition must not is null"); if (beandefinition instanceof abstractbeandefinition {try {(abstractbeandefinition) beandefinition). Validate ();} catch (Beandefinitionvalidationexception ex) {throw new Beandefinitionstoreexception ( Beandefinition.getresourcedescription (), Beanname, "Validation of bean definition failed", ex);}} Beandefinition oldbeandefinition;synchronized (this.beandefinitionmap) {oldbeandefinition = This.beanDefinitionMap.get (Beanname); if (oldbeandefinition! = null) {if (!this.allowbeandefinitionoverriding) {throw New Beandefinitionstoreexception (beandefinition.getresourcedEscription (), Beanname, "Cannot register bean definition [" + beandefinition + "] for beans '" + beanname + "': there is alre Ady ["+ Oldbeandefinition +"] bound. ");  else {if (this.logger.isInfoEnabled ()) {this.logger.info ("overriding bean definition for bean '" + beanname + "': replacing ["+ Oldbeandefinition +"] with ["+ Beandefinition +"] ");}}} else {this.beanDefinitionNames.add (beanname); this.frozenbeandefinitionnames = null;} This.beanDefinitionMap.put (Beanname, beandefinition);} if (oldbeandefinition! = NULL | | Containssingleton (beanname)) {resetbeandefinition (beanname);}}

1) Check the abstractbeandefinition. In parsing the XML file we have checked, before the XML format of the checksum, now do the check is the abstractbeandefinition of the Methodoverrides 2) to the Beanname has registered the situation to do the processing, If the bean is set to not be allowed to overwrite, then the exception is thrown directly, otherwise it is directly overwritten with 3) to join the map cache 4) to clearly parse the previously left Beanname cache.
Registering beandefinition by aliases alias first we look at the specific code implementation:
public void Registeralias (string name, string alias) {Assert.hastext (name, "' Name ' must ' is empty"); Assert.hastext (alias, "' Alias ' must not is empty"); if (alias.equals (name)) {this.aliasMap.remove (alias);} else {if (!allowaliasoverriding ()) {String registeredname = This.aliasMap.get (alias); if (registeredname! = null && amp;!registeredname.equals (name)) {throw new IllegalStateException ("Cannot register alias '" + Alias + "' for Name '" +na Me + "': It is already registered for name '" + Registeredname + "'.");} Checkforaliascircle (name, alias); This.aliasMap.put (alias, name);}}

1) Alias and beanname name the same case processing, if the name is the same, then directly delete the alias. 2) alias overwrite processing. If AliasName has pointed to another beanname it needs to be processed by the user's settings. 3) alias Loop check. When the a->b exists, the a->c->b throws an exception if it occurs. 4) Register Alias

Notification Listener resolution registration completedLet's review the Processbeandefinition method, which says that when the bean registration is complete, getreadercontext () is called. Firecomponentregistered (New Beancomponentdefinition (Bdholder)); This provides a way for developers to expand after the bean has been registered, and there is now a null implementation in spring.

SummarizeAbove only the Spring Bean label parsing, other default tags, such as Import,alias,beans tags, in fact, the same way of parsing, if you want to explore a friend can follow the program source code to walk a few times.Spring default label parsing and registration of the general logic so, in fact, seriously read the source of the students, it is easy to understand the logic inside, it seems complex, in fact, it is not difficult, but one can agree that the source code of spring is indeed very rigorous, it is worth learning.

Spring source Analysis (ii) Spring default label parsing and registration implementation

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.