Analysis of spring parsing bean tag process

write in front

This article continues the analysis on the basis of this article. This article mainly analyzes the parsing process of bean tags.

1: role

Needless to say, configure spring beans.

2: Test code

For the convenience of debugging, paste the test code:

@Test 
public  void  testBeanDefinitionLoad ( )  { 
    // Define resource 
    ClassPathResource classPathResource =  new  ClassPathResource ( "testbeandefinition.xml" ) ; 
    // Define IOC container 
    DefaultListableBeanFactory defaultListableBeanFactory =  new  DefaultListableBeanFactory ( ) ; 
    // Define bean definition reader 
    XmlBeanDefinitionReader xmlBeanDefinitionReader =  new  XmlBeanDefinitionReader ( defaultListableBeanFactory ) ; // Read bean definition 
    int from resource through bean definition reader
    i = xmlBeanDefinitionReader . loadBeanDefinitions ( classPathResource ) ; 
    System . out . println ( "The number of bean definitions is: "  + i ) ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

xml:

<?xml version="1.0" encoding="UTF-8"?> 
< beans  xmlns = " http://www.springframework.org/schema/beans " 
       xmlns: xsi = " http://www.w3.org /2001/XMLSchema-instance " 
       xsi: schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd " > 
    < bean  id = " testBeanDefinitionBean "  class = " yudaosourcecode.spring.TestBeanDefinitionBean " /> 
    <bean  id= " testBeanDefinitionBean1 "  class = " yudaosourcecode.spring.TestBeanDefinitionBean " /> 
</ beans >
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

then inorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElementHit the following breakpoint to start debugging:
insert image description here

3: processBeanDefinition

Source code:

org . springframework . beans . factory . xml . DefaultBeanDefinitionDocumentReader#processBeanDefinition
 protected  void  processBeanDefinition ( Element ele , BeanDefinitionParserDelegate delegate )  { 
	// <2021-03-01 13:36> 
	// Get the DeanDefinitionHolder instance object that holds the name and alias 
	BeanDefinitionHolder bdHolder = delegate . parseBeanDefinitionElement ( ele ) ; 
	// get 
	if  ( bdHolder != null )  {
		// Do custom label processing, such as id, name, class, lazy-init, etc., it does not affect the main process, let's not delve into 
		bdHolder = delegate . decorateBeanDefinitionIfRequired ( ele , bdHolder ) ; 
		try  { 
			// Register BeanDefinition 
			BeanDefinitionReaderUtils . registerBeanDefinition ( bdHolder ,  getReaderContext ( ) . getRegistry ( ) ) ; 
		} 
		catch  ( BeanDefinitionStoreException ex )  { 
			getReaderContext ( ) . error( "Failed to register bean definition with name '"  + 
					bdHolder . getBeanName ( )  +  "'" , ele , ex ) ; 
		} 
		// fire event 
		getReaderContext ( ) . fireComponentRegistered ( new  BeanComponentDefinition ( bdHolder ) ) ; 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

<2021-03-01 13:36>see code3.1: parseBeanDefinitionElement

3.1: parseBeanDefinitionElement

Source code:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # parseBeanDefinitionElement ( org.w3c.dom.Element ) public BeanDefinitionHolder parseBeanDefinitionElement ( Element ele ) { return parseBeanDefinitionElement ( ele , null ) ; } _ _ _ _ _ _ _ _ _ _ _ _ _ _
 
	 

  • 1
  • 2
  • 3
  • 4

continue:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # parseBeanDefinitionElement ( org.w3c.dom.Element , org.springframework.beans.factory.config.BeanDefinition ) @Nullable public BeanDefinitionHolder parseBeanDefinitionElement ( Element ele , @Nullable BeanDefinition containingBean ) { _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

  
	// Get the id attribute 
	String id = ele . getAttribute ( ID_ATTRIBUTE ) ; 
	// Get the name attribute 
	String nameAttr = ele . getAttribute ( NAME_ATTRIBUTE ) ; 
	// <2021-03-02 17:47> 
	List < String > aliases =  new  ArrayList < > ( ) ; 
	if  ( StringUtils . hasLength ( nameAttr ) )  { 
		String [ ] nameArr= StringUtils . tokenizeToStringArray ( nameAttr , MULTI_VALUE_ATTRIBUTE_DELIMITERS ) ; 
		aliases . addAll ( Arrays . asList ( nameArr ) ) ; 
	} 
	// By default, the id is used as the bean name, that is, the id attribute takes precedence over the name attribute 
	String beanName = id ; 
	// if If the id is not set and the name attribute is set, the first one is taken as the beanName 
	if  ( ! StringUtils . hasText ( beanName )  &&  ! aliases . isEmpty ( ))  { 
		// take out and remove the first one as beanName 
		beanName = aliases . remove ( 0 ) ; 
		if  ( logger . isTraceEnabled ( ) )  { 
			logger . trace ( "No XML 'id' specified - using '"  + beanName + 
					"' as bean name and "  + aliases +  " as aliases" ) ; 
		} 
	} 
	// <2021-03-02 17:52> 
	if  ( containingBean == null )  {
		checkNameUniqueness ( beanName , aliases , ele ) ; 
	} 
	// <2021-03-02 17:53> 
	AbstractBeanDefinition beanDefinition =  parseBeanDefinitionElement ( ele , beanName , containingBean ) ; 
	// parsed out beandefinition successfully 
	if  ( beanDefinition != null )  { 
		// This part is to use the default rules to generate the bean name when neither id nor name has a value. It is not important and can be ignored 
		if  ( ! StringUtils . hasText ( beanName ) )  { 
			try { 
				if  ( containingBean != null )  { 
					beanName = BeanDefinitionReaderUtils . generateBeanName ( 
							beanDefinition ,  this . readerContext . getRegistry ( ) ,  true ) ; 
				} 
				else  { 
					beanName =  this . readerContext . generateBeanName ( beanDefinition ) ; 
					String beanClassName = beanDefinition .getBeanClassName ( ) ; 
					if  ( beanClassName != null && 
							beanName . startsWith ( beanClassName )  && beanName . length ( )  > beanClassName . length ( )  && 
							! this . readerContext . getRegistry ( ) . isBeanNameInUse ( beanClassName ) ) { 
						aliases . add ( beanClassName ) ; 
					} 
				} 
				if  ( logger . isTraceEnabled ( ) )  { 
					logger . trace ( "Neither XML 'id' nor 'name' specified - "  + 
							"using generated bean name ["  + beanName +  "]" ) ; 
				} 
			} 
			catch  ( Exception ex )  { 
				error ( ex . getMessage ( ) , ele ) ; 
				return null ;
			} 
		} 
		// Aliases array 
		String [ ] aliasesArray = StringUtils . toStringArray ( aliases ) ; 
		// Construct BeanDefinitionHolder using beandefinition, bean name, aliases array as parameters 
		return  new  BeanDefinitionHolder ( beanDefinition , beanName , aliasesArray ) ; 
	}

	return null ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

<2021-03-02 17:47>The place is to use the name attribute of the configuration as an alias, as follows:

< bean  id = " testBeanDefinitionBean "  class = " yudaosourcecode.spring.TestBeanDefinitionBean "
    name = " name_1,name_2,name_3 " />
  • 1
  • 2

The debug result is as follows:
insert image description here
<2021-03-02 17:52>refer to3.2: checkNameUniqueness,<2021-03-02 17:53>see3.3: parseBeanDefinitionElement(ele, beanName, containingBean)

3.2: checkNameUniqueness

Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#checkNameUniqueness
 protected  void  checkNameUniqueness ( String beanName , List < String > aliases , Element beanElement )  { 
	// existing bean name 
	String foundName = null ; 
	// if passed in bean The name is not empty, and it has been included with the name, then assign the current 
	// bean name to the existing bean name 
	if  ( StringUtils . hasText ( beanName )  && this . usedNames . contains ( beanName ) )  { 
		foundName = beanName ; 
	} 
	// if it is not found from the passed in bean name, try to find it from the alias array 
	if  ( foundName == null )  { 
		foundName = CollectionUtils . findFirstMatch ( this .usedNames , aliases ) ; } // if exists, throw an error if ( foundName ! = null ) { error (
	
	
	  
		"Bean name '"  + foundName +  "' is already used in this <beans> element" , beanElement ) ; 
	} 
	// Add the passed bean name to the used set 
	this . usedNames . add ( beanName ) ; 
	// Adds all aliases to the used set 
	this . usedNames . addAll ( aliases ) ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3.3: parseBeanDefinitionElement(ele, beanName, containingBean)

Source code:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # parseBeanDefinitionElement ( org.w3c.dom.Element , java.lang.String , org.springframework.beans.factory.config.BeanDefinition ) public AbstractBeanDefinition parseBeanDefinitionElement ( Element 
		ele , _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
String beanName ,  @Nullable BeanDefinition containingBean )  {

	this . parseState . push ( new  BeanEntry ( beanName ) ) ; 
	// parse the class name 
	String className = null ; 
	if  ( ele . hasAttribute ( CLASS_ATTRIBUTE ) )  { 
		className = ele . getAttribute ( CLASS_ATTRIBUTE ) . trim ( ) ; 
	} 
	// < 2021-03-02 19:01> 
	// Set parent property 
	String parent = null ;
	if  ( ele . hasAttribute ( PARENT_ATTRIBUTE ) )  { 
		parent = ele . getAttribute ( PARENT_ATTRIBUTE ) ; 
	}

	try  { 
		// <2021-03-02 19:08> 
		// Create a beandefinition for carrying configuration information 
		AbstractBeanDefinition bd =  createBeanDefinition ( className , parent ) ; 
		// Parse various attributes 
		parseBeanDefinitionAttributes ( ele , beanName , containingBean , bd ) ; 
		// set description 
		bd . setDescription ( DomUtils . getChildElementValueByTagName ( ele , DESCRIPTION_ELEMENT ) ) ; 
		/*** Parse the inner child element of the bean tag starts ***/
		// <2021-03-03 14:42> 
		// Parse metadata <meta /> 
		parseMetaElements ( ele , bd ) ; 
		// <2021-03-03 14:43> 
		// Parse lookup-method 
		parseLookupOverrideSubElements ( ele , bd . getMethodOverrides ( ) ) ; 
		// <2021-03-03 14:44> 
		// parse the replaced-method 
		parseReplacedMethodSubElements ( ele , bd . getMethodOverrides ( ) ) ; 
		// <2021-03-04 18:39> 
		// parse constructor-arg 
		parseConstructorArgElements ( ele, bd ) ; 
		// <2021-03-04 18:42> 
		// Parse property 
		parsePropertyElements ( ele , bd ) ; 
		// <2021-03-04 18:43> 
		// Parse qualifier 
		parseQualifierElements ( ele , bd ) ; 
		/*** End of parsing inner child element of bean tag ***/

		bd . setResource ( this . readerContext . getResource ( ) ) ; 
		bd . setSource ( extractSource ( ele ) ) ;

		return bd ; 
	} 
	catch  ( ClassNotFoundException ex )  { 
		error ( "Bean class ["  + className +  "] not found" , ele , ex ) ; 
	} 
	catch  ( NoClassDefFoundError err )  { 
		error ( "Class that bean class ["  + className +  "] depends on not found" , ele , err ) ; 
	} 
	catch  ( Throwable ex)  { 
		error ( "Unexpected failure during bean definition parsing" , ele , ex ) ; 
	} 
	finally  { 
		this . parseState . pop ( ) ; 
	}

	return null ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

<2021-03-02 19:01>Set the parent property, you can refer to here for the parent property .<2021-03-02 19:08>refer to3.4: createBeanDefinition.<2021-03-03 14:42>reference4.1: meta subtag parsing,<2021-03-03 14:43>reference4.2: Lookup-method sub-tag parsing,<2021-03-03 14:44>reference codeReplaced-method Subtag Analysis,<2021-03-04 18:39>reference4.4: constructor-arg subtag parsing,<2021-03-04 18:42>reference4.5: Analysis of property subtags,<2021-03-04 18:43>reference4.6: qualifier subtag parsing.

3.4: createBeanDefinition

The top-level interface of BeanDefinition isorg.springframework.beans.factory.config.BeanDefinition, the method returns its implementation classorg.springframework.beans.factory.support.GenericBeanDefinition, see the source code:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate #
 createBeanDefinition protected AbstractBeanDefinition createBeanDefinition ( @Nullable String className , @Nullable String parentName ) throws ClassNotFoundException { _ _ _ _ _ _ 
			

	return BeanDefinitionReaderUtils . createBeanDefinition ( 
			parentName , className ,  this . readerContext . getBeanClassLoader ( ) ) ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

continue:

org.springframework.beans.factory.support.BeanDefinitionReaderUtils #
 createBeanDefinition public static AbstractBeanDefinition createBeanDefinition ( @Nullable String parentName , @Nullable String className , @Nullable ClassLoader classLoader ) throws ClassNotFoundException { _ _ _ _ _ 
			   

	GenericBeanDefinition bd =  new  GenericBeanDefinition ( ) ; 
	bd . setParentName ( parentName ) ; 
	if  ( className != null )  { 
		if  ( classLoader != null )  { 
			bd . setBeanClass ( ClassUtils . forName ( className , classLoader ) ) ; 
		} 
		else  { 
			bd . setBeanClassName( className ) ; 
		} 
	} 
	return bd ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Created directly using the tool classGenericBeanDefinitioninstance.

4: bean sub-tag resolution

4.1: meta subtag parsing

The meta tag is just a way to supplement information and will not be reflected in the final generated bean object.
Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parseMetaElements
 public  void  parseMetaElements ( Element ele , BeanMetadataAttributeAccessor attributeAccessor )  { 
	// Get all the sub-tags of the current bean tag, of course, only the <meta> sub-tags in it will be processed later 
	NodeList nl = ele .getChildNodes ( ) ; for ( int i = 0 ; i < nl .getLength ( ) ; _ _
	  i ++ )  { 
		Node node = nl . item ( i ) ; 
		// Here isCandidateElement must be an element in the default namespace, ie 
		// http://www.springframework.org/schema/beans namespace 
		// nodeNameEquals (node, META_ELEMENT) The judgment must be a meta tag 
		// which is the tag to be parsed by this method 
		// such as: <meta key="key1" value="value1"/> 
		if  ( isCandidateElement ( node )  &&  nodeNameEquals ( node , META_ELEMENT ) )  { 
			// 
			cast Element metaElement =  ( Element ) node; 
			// Get key 
			String key = metaElement . getAttribute ( KEY_ATTRIBUTE ) ; 
			// Get value 
			String value = metaElement . getAttribute ( VALUE_ATTRIBUTE ) ; 
			// Encapsulate key+value as BeanMetadataAttribute 
			BeanMetadataAttribute attribute =  new  BeanMetadataAttribute ( key , value ) ; 
			/ / The final call of extractSource(metaElement) is to return null directly, so you can temporarily ignore 
			attribute . setSource ( extractSource (metaElement ) ) ; 
			// <2021-03-03 15:32> 
			attributeAccessor . addMetadataAttribute ( attribute ) ; 
		} 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

<2021-03-03 15:32>The type of the input parameter of attributeAccessor isAbstractBeanDefinition, but it inheritsBeanMetadataAttributeAccessor,as follows:

public  abstract  class  AbstractBeanDefinition  extends  BeanMetadataAttributeAccessor 
		implements  BeanDefinition , Cloneable { }
  • 1
  • 2

therefore haveBeanMetadataAttributeAccessorAbility,addMetadataAttributeThe source code is as follows:

org.springframework.beans.BeanMetadataAttributeAccessor #
 addMetadataAttribute public void addMetadataAttribute ( BeanMetadataAttribute attribute ) { super.setAttribute ( attribute.getName ( ) , attribute ) ; } _ _ _ _ _ _ _   
	

  • 1
  • 2
  • 3
  • 4

continue:

org . springframework . core . AttributeAccessorSupport#setAttribute
 @Override 
public  void  setAttribute ( String name ,  @Nullable Object value )  { 
	Assert . notNull ( name ,  "Name must not be null" ) ; 
	if  ( value != null )  { 
		// private final Map<String, Object> attributes = new LinkedHashMap<>(); 
		this . attributes . put ( name ,value ) ; 
	} 
	else  { 
		removeAttribute ( name ) ; 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

finally store the information inorg.springframework.core.AttributeAccessorSupportin the map collection.

4.2: Lookup-method sub-tag parsing

aboutlookup-methodThe usage can be found here .
Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parseLookupOverrideSubElements
 public  void  parseLookupOverrideSubElements ( Element beanEle , MethodOverrides overrides )  { 
	// get child nodes 
	NodeList nl = beanEle . getChildNodes ( ) ; 
	for  ( int i =  0 ; i < nl . getLength ( ) ; i++ )  { 
		Node node = nl . item ( i ) ; 
		if  ( isCandidateElement ( node )  &&  nodeNameEquals ( node , LOOKUP_METHOD_ELEMENT ) )  { 
			Element ele =  ( Element ) node ; 
			// The name property is the name of the method to call to get the bean 
			String methodName = ele . getAttribute ( NAME_ATTRIBUTE ) ; 
			// bean attribute is the bean name of the bean to return
			String beanRef = ele . getAttribute ( BEAN_ELEMENT ) ; 
			// Construct LookupMethod object by method name and bean name 
			LookupOverride override =  new  LookupOverride ( methodName , beanRef ) ; 
			override . setSource ( extractSource ( ele ) ) ; 
			// <2021-03-03 16:59 > 
			overrides.addOverride ( override ) ; } } } _
		
	

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

<2021-03-03 16:59>It is to add lookup-method information, that is, override to overrides. Overrides is a container object that stores LookupOverride. The source code is as follows:

org.springframework.beans.factory.support.MethodOverrides
 public class MethodOverrides { _ _ _ _ _ _ _ _ _ _   

	private  final Set < MethodOverride > overrides =  new  CopyOnWriteArraySet < > ( ) ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5

4.3: Replaced-method Subtag Parsing

The specific usage can be found here .
Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parseReplacedMethodSubElements
 public  void  parseReplacedMethodSubElements ( Element beanEle , MethodOverrides overrides )  { 
	// Get all elements of the bean tag 
	NodeList nl = beanEle . getChildNodes ( ) ; 
	for  ( int i =  0 ; i < nl.getLength ( ) ; i _ _++ )  { 
		Node node = nl . item ( i ) ; 
		/// The replaced-method tag in the default namespace is processed 
		if  ( isCandidateElement ( node )  &&  nodeNameEquals ( node , REPLACED_METHOD_ELEMENT ) )  { 
			// Forced 
			Element replacedMethodEle =  ( Element ) node ; 
			// Get the name of the method to be replaced 
			String name = replacedMethodEle . getAttribute ( NAME_ATTRIBUTE ); 
			// The name of the bean to perform the specific replacement operation 
			String callback = replacedMethodEle . getAttribute ( REPLACER_ATTRIBUTE ) ; 
			// Construct the ReplaceOverride object 
			ReplaceOverride replaceOverride =  new  ReplaceOverride ( name , callback ) ; 
			// Get the child element arg-type, it is not clear how to use it , use it and look at 
			List < Element > argTypeEles = DomUtils . getChildElementsByTagName ( replacedMethodEle , ARG_TYPE_ELEMENT ) ; 
			// Loop through the arg-type sub-tags and process the match attribute in them
			for  ( Element argTypeEle : argTypeEles )  { 
				String match = argTypeEle . getAttribute ( ARG_TYPE_MATCH_ATTRIBUTE ) ; 
				match =  ( StringUtils . hasText ( match )  ? match : DomUtils . getTextValue ( argTypeEle ) ) ; 
				if  ( StringUtils . hasText ( match ) )  { 
					replaceOverride. addTypeIdentifier ( match ) ; 
				} 
			} 
			replaceOverride . setSource ( extractSource ( replacedMethodEle ) ) ; 
			overrides . addOverride ( replaceOverride ) ; 
		} 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

4.4: constructor-arg subtag parsing

This method is equivalent to assigning the constructor to let spring call to create the object.
The xml configuration file used for the test is as follows:

<?xml version="1.0" encoding="UTF-8"?> 
< beans  xmlns = " http://www.springframework.org/schema/beans " 
       xmlns: xsi = " http://www.w3.org /2001/XMLSchema-instance " 
       xsi: schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd " > 
    < bean  id = " bookService "  class = " yudaosourcecode.constructorarg.BookService " />

    < bean  id = " studentService "  class = " yudaosourcecode.constructorarg.StudentService " > 
        < constructor-arg  index = " 0 "  value = " chenssy " /> 
        < constructor-arg  name = " age "  value = " 100 " /> 
        < constructor-arg  name = " bookService " ref = " bookService" /> 
    </ beans > 
</ beans >
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parseConstructorArgElements
 public  void  parseConstructorArgElements ( Element beanEle , BeanDefinition bd )  { 
	NodeList nl = beanEle . getChildNodes ( ) ; 
	// Traverse all tags, if it is constructor-arg in the default namespace 
	// Then call the parseConstructorArgElement method to process 
	for  ( int i =  0 ; i < nl . getLength( ) ; i ++ )  { 
		Node node = nl . item ( i ) ; 
		if  ( isCandidateElement ( node )  &&  nodeNameEquals ( node , CONSTRUCTOR_ARG_ELEMENT ) )  { 
			parseConstructorArgElement ( ( Element ) node , bd ) ; 
		} 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

let's seeparseConstructorArgElementMethod source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parseConstructorArgElement
 public  void  parseConstructorArgElement ( Element ele , BeanDefinition bd )  { 
	// Parse the index attribute, set the constructor parameter 
	String by position indexAttr = ele . getAttribute ( INDEX_ATTRIBUTE ) ; 
	// Parse the type Attribute , set constructor parameter by type 
	String typeAttr = ele.getAttribute ( TYPE_ATTRIBUTE ) ;
	// Parse the name attribute, set the constructor parameter by name 
	String nameAttr = ele . getAttribute ( NAME_ATTRIBUTE ) ; 
	// if the index position is set 
	if  ( StringUtils . hasLength ( indexAttr ) )  { 
		try  { 
			int index = Integer . parseInt ( indexAttr ) ; 
			// Judge not less than 0 
			if  ( index <  0 )  { 
				error ( "'index' cannot be lower than 0" , ele ); 
			} 
			else  { 
				try  { 
					// Store the index information in parseState, where ConstructorArgumentEntry 
					// represents the parameter information of the constructor, such as parameter position, parameter name, parameter type, etc. 
					this . parseState . push ( new  ConstructorArgumentEntry ( index ) ) ; 
					// <2021-03-05 11:19> 
					// Parse the properties in the constructor-arg, such as ref, value, etc. 
					// In fact, it is to obtain the value of the constructor parameter when the bean is created later 
					Object value =  parsePropertyValue ( ele , bd , null ) ; 
					// Construct the object of the value of the constructor parameter according to value ConstructorArgumentValues ​​object information 
					ConstructorArgumentValues.ValueHolder valueHolder =  new  ConstructorArgumentValues ​​.ValueHolder ( value ) ; 
					// if there is a type attribute 
					if  ( StringUtils . hasLength ( typeAttr ) ) { 
						valueHolder . setType ( typeAttr ) ; } // if there is a name attribute if ( StringUtils . hasLength ( nameAttr ) ) { 
						valueHolder . setName ( nameAttr ) 
					
					
					  ; 
					} 
					valueHolder . setSource ( extractSource ( ele ) ) ; 
					// Determine if there is an index position in the map where the index position of the constructor -> value is stored. 
					// If it does, it will be an exception, that is, if there is a duplicate index definition 
					if  ( bd .getConstructorArgumentValues ​​( ) . hasIndexedArgumentValue ( index ) ) { error ( " Ambiguous constructor-arg entries for index " + index , ele ) ; } else { // Store the constructor argument index position -> value information in map 
						bd . 
						 
					
					 
						getConstructorArgumentValues ​​( ) . addIndexedArgumentValue ( index , valueHolder ) ; 
					} 
				} 
				finally  { 
					this . parseState . pop ( ) ; 
				} 
			} 
		} 
		catch  ( NumberFormatException ex )  { 
			error ( "Attribute 'index' of tag 'constructor-arg' must be an integer " , ele ) ; 
		} 
	} 
	// if index is not set 
	else  { 
		try  { 
			this.parseState .push ( new ConstructorArgumentEntry ( ) ) ; // Parse the value that needs to be assigned to the constructor parameter 
			Object value = parsePropertyValue ( ele , bd , null ) ; // Create an object that encapsulates the value of the constructor parameter 
			ConstructorArgumentValues ​​. ValueHolder valueHolder = new ConstructorArgumentValues ​​. ValueHolder ( value ) ; // has type, set type if ( StringUtils . hasLength ( typeAttr 
			 
			  
			
			 ) )  { 
				valueHolder . setType ( typeAttr ) ; 
			} 
			// has name, set name 
			if  ( StringUtils . hasLength ( nameAttr ) )  { 
				valueHolder . setName ( nameAttr ) ; 
			} 
			valueHolder . setSource ( extractSource ( ele ) ) ; 
			// store value Information, the way to store values ​​is different from the case of using index 
			// The index method stores the information of position->value, which stores the information of name->value 
			bd . getConstructorArgumentValues( ) . addGenericArgumentValue ( valueHolder ) ; 
		} 
		finally  { 
			this . parseState . pop ( ) ; 
		} 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

<2021-03-05 11:19>The place is to parse the constructor-arg sub-elements and attribute information, the source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parsePropertyValue
 public Object parsePropertyValue ( Element ele , BeanDefinition bd ,  @Nullable String propertyName )  { 
	// Use 
	String elementName =  ( propertyName != null ? 
			"<property > element for property '"  + propertyName +  "'"  : 
			"<constructor-arg> element" ) ;

	// There are several ways to assign values ​​to constructor parameters. 
	// 1: ref attribute 2: value attribute 3: ref sub-element 4: value sub-element 5: list sub-element, etc. 
	// The following is mainly to judge that there can only be one assignment method kind , otherwise it will conflict 
	NodeList nl = ele . getChildNodes ( ) ; 
	Element subElement = null ; 
	// loop through the child elements of constructor-arg 
	for  ( int i =  0 ; i < nl . getLength ( ) ; i ++ )  { 
		Node node = nl . item ( i ) ;
		// Ignore description sub-element, meta sub-element 
		if  ( node instanceof  Element  &&  ! nodeNameEquals ( node , DESCRIPTION_ELEMENT )  && 
				! nodeNameEquals ( node , META_ELEMENT ) )  { 
			// If the sub-element is not empty, it means you have multiple sub-elements , this case is directly abnormal 
			if  ( subElement != null )  { 
				error ( elementName +  " must not contain more than one sub-element" , ele ) ; 
			} 
			// If the sub-element has no value, the assignment is currently the sub-element
			else  { 
				subElement =  ( Element ) node ; 
			} 
		} 
	} 
	// Whether there is a ref attribute (one of the ways to assign values ​​to constructor parameters) 
	boolean hasRefAttribute = ele . hasAttribute ( REF_ATTRIBUTE ) ; 
	// Whether there is a value attribute (for the constructor One of the ways of parameter assignment) 
	boolean hasValueAttribute = ele . hasAttribute ( VALUE_ATTRIBUTE ) ; 
	// The following situations will lead to conflicts in the assignment of constructor parameters, direct exception 
	// 1: There are both ref attributes and value attributes 
	// 2: There is one of the ref attribute and the value attribute, and there are child elements 
	if  ( ( hasRefAttribute&& hasValueAttribute )  || 
			( ( hasRefAttribute || hasValueAttribute )  && subElement != null ) )  { 
		error ( elementName + 
				" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element" , ele ) ; 
	} 
	// If there is a ref attribute 
	if  ( hasRefAttribute )  { 
		// Get the value of ref 
		String refName = ele . getAttribute ( REF_ATTRIBUTE ) ;
		// If the ref value has no content, an exception 
		if  ( ! StringUtils . hasText ( refName ) )  { 
			error ( elementName +  " contains empty 'ref' attribute" , ele ) ; 
		} 
		// Define the RuntimeBeanReference object and encapsulate the value information of ref 
		RuntimeBeanReference ref =  new  RuntimeBeanReference ( refName ) ; 
		ref . setSource ( extractSource ( ele ) ) ; 
		// Returns the object encapsulated with ref value information, which is then used to assign values ​​to constructor parameters using 
		returnref ; 
	} 
	// has value attribute 
	else  if  ( hasValueAttribute )  { 
		// encapsulate the value of value into TypedStringValue object and return 
		TypedStringValue valueHolder =  new  TypedStringValue ( ele . getAttribute ( VALUE_ATTRIBUTE ) ) ; 
		valueHolder . setSource ( extractSource ( ele ) ) ; // Return the object encapsulated with value information, and then use 
		return valueHolder to assign values ​​to constructor parameters 
		; } // If it is a child element else if (
	
	
	  subElement != null )  { 
		// <2021-03-05 13:24> 
		// Further parse the sub-element to get the object that can be assigned to the constructor parameter 
		return  parsePropertySubElement ( subElement , bd ) ; 
	} 
	else  { 
		error ( elementName +  " must specify a ref or value" , ​​ele ) ; 
		return null ; 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

<2021-03-05 13:24>The point is to deal with the case where there are no value and ref attributes, but values ​​are provided to constructor parameters through sub-elements. For details, refer to4.4.1: parsePropertySubElement.

4.4.1: parsePropertySubElement

This method parses the value that needs to be provided to the constructor parameter through the subtag of constructor-arg. Source code:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # parsePropertySubElement ( org.w3c.dom.Element , org.springframework.beans.factory.config.BeanDefinition ) public Object parsePropertySubElement ( Element ele , @Nullable BeanDefinition bd ) { return _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  
	 parsePropertySubElement ( ele , bd , null ) ; 
}
  • 1
  • 2
  • 3
  • 4

continue:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # parsePropertySubElement ( org.w3c.dom.Element , org.springframework.beans.factory.config.BeanDefinition , java.lang.String ) public Object parsePropertySubElement ( Element ele , @Nullable _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 BeanDefinition bd ,  @Nullable String defaultValueType )  { 
	// Not the default namespace, usually 
	if  ( ! isDefaultNamespace ( ele ) )  { 
		return  parseNestedCustomElement ( ele , bd ) ; 
	} 
	// If it is a bean tag, call the bean tag parsing process 
	else  if  ( nodeNameEquals ( ele , BEAN_ELEMENT ) )  { 
		BeanDefinitionHolder nestedBd =  parseBeanDefinitionElement ( ele , bd) ; 
		if  ( nestedBd != null )  { 
			nestedBd =  decorateBeanDefinitionIfRequired ( ele , nestedBd , bd ) ; 
		} 
		return nestedBd ; 
	} 
	// if ref 
	else  if  ( nodeNameEquals ( ele , REF_ELEMENT ) )  { 
		// A generic reference to any name of any bean.String 
		refName = ele.getAttribute ( BEAN_REF_ATTRIBUTE ); 
		boolean toParent =  false ; 
		if  ( ! StringUtils . hasLength ( refName ) )  { 
			// A reference to the id of another bean in a parent context. 
			refName = ele . getAttribute ( PARENT_REF_ATTRIBUTE ) ; 
			toParent =  true ; 
			if  ( ! StringUtils . hasLength ( refName ) )  { 
				error ("'bean' or 'parent' is required for <ref> element" , ele ) ; 
				return null ; 
			} 
		} 
		if  ( ! StringUtils . hasText ( refName ) )  { 
			error ( "<ref> element contains empty target attribute" , ele ) ; 
			return null ; 
		} RuntimeBeanReference 
		ref =  new  RuntimeBeanReference ( refName , toParent ) ; 
		ref .setSource( extractSource ( ele ) ) ; 
		return ref ; 
	} 
	// if idref 
	else  if  ( nodeNameEquals ( ele , IDREF_ELEMENT ) )  { 
		return  parseIdRefElement ( ele ) ; 
	} 
	// if value 
	else  if  ( nodeNameEquals ( ele , VALUE_ELEMENT ) )  { 
		return  parseValueElement ( ele , defaultValueType ); 
	} 
	// If it is a null tag, it should be used to assign a null value 
	else  if  ( nodeNameEquals ( ele , NULL_ELEMENT ) )  { 
		// It's a distinguished null value. Let's wrap it in a TypedStringValue 
		// object in order to preserve the source location.TypedStringValue 
		nullHolder =  new  TypedStringValue ( null ) ; 
		nullHolder .setSource ( extractSource ( ele ) ) ; return nullHolder ; } // if array else
		
	
	
	 if  ( nodeNameEquals ( ele , ARRAY_ELEMENT ) )  { 
		return  parseArrayElement ( ele , bd ) ; 
	} 
	// if list 
	else  if  ( nodeNameEquals ( ele , LIST_ELEMENT ) )  { 
		return  parseListElement ( ele , bd ) ; 
	} 
	// if set 
	else  if  ( nodeNameEquals ( ele , SET_ELEMENT ))  { 
		return  parseSetElement ( ele , bd ) ; 
	} 
	// if map 
	else  if  ( nodeNameEquals ( ele , MAP_ELEMENT ) )  { 
		return  parseMapElement ( ele , bd ) ; 
	} 
	// if props 
	else  if  ( nodeNameEquals ( ele , PROPS_ELEMENT ) )  { 
		return  parsePropsElement ( ele ) ;
	} 
	else  { 
		error ( "Unknown property sub-element: ["  + ele . getNodeName ( )  +  "]" , ele ) ; 
		return null ; 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

Different analysis is performed according to different element types, and the final result is that the information that can be assigned to the constructor parameters is obtained and returned.

4.5: Analysis of property subtags

In this way, spring will create an object through a parameterless constructor, and then call the corresponding writer method according to the configuration of the property tag to assign a value to the property. Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parsePropertyElements
 public  void  parsePropertyElements ( Element beanEle , BeanDefinition bd )  { 
	// get all child nodes 
	NodeList nl = beanEle . getChildNodes ( ) ; 
	// loop through all default namespaces property element 
	for  ( int i =  0 ; i < nl . getLength ( ) ;i ++ )  { 
		Node node = nl . item ( i ) ; 
		if  ( isCandidateElement ( node )  &&  nodeNameEquals ( node , PROPERTY_ELEMENT ) )  { 
			// <2021-03-05 15:20> 
			// process property element 
			parsePropertyElement ( ( Element ) node , bd ) ; 
		} 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

<2021-03-05 15:20>source code reference4.5.1: parsePropertyElement.

4.5.1: parsePropertyElement

Source code:

org . springframework . beans . factory . xml . BeanDefinitionParserDelegate#parsePropertyElement
 public  void  parsePropertyElement ( Element ele , BeanDefinition bd )  { 
	// Get the value of the name attribute, which is the name of the attribute 
	String propertyName = ele . getAttribute ( NAME_ATTRIBUTE ) ; 
	// attribute name value required 
	if  ( ! StringUtils . hasLength ( propertyName ) )  { 
		error ("Tag 'property' must have a 'name' attribute" , ele ) ; 
		return ; 
	} 
	this . parseState . push ( new  PropertyEntry ( propertyName ) ) ; 
	try  { 
		// Check for duplicate name values, if there is an exception 
		if  ( bd . getPropertyValues ​​( ) . contains ( propertyName ) )  { 
			error ( "Multiple 'property' definitions for property '"  + propertyName +  "'" ,ele ) ; 
			return ; 
		} 
		// Get the object that encapsulates the property value 
		Object val =  parsePropertyValue ( ele , bd , propertyName ) ; 
		// Create the object that encapsulates "property name -> property value object" 
		PropertyValue pv =  new  PropertyValue ( propertyName , val ) ; 
		parseMetaElements ( ele , pv ) ; 
		pv .setSource ( extractSource ( ele ) ) ; _
		// Store the object encapsulated with "property name -> property value object" to beandefinition's 
		// corresponding data structure 
		bd . getPropertyValues ​​( ) . addPropertyValue ( pv ) ; 
	} 
	finally  { 
		this . parseState . pop ( ) ; 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

4.6: qualifier subtag parsing

Temporarily omitted.

5: Bean custom tag parsing

For custom tags, you can refer to spring's custom tags
, and spring intervenes in the bean generation process through custom tags
.
Briefly review the previous process, in the methodorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinitionComplete the work of parsing the bean tag in , first pass the following codeBeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);Complete the work of parsing the default tags, and then the next step is to parse the custom tags, look at the source code:

org . springframework . beans . factory . xml . DefaultBeanDefinitionDocumentReader#processBeanDefinition
 protected  void  processBeanDefinition ( Element ele , BeanDefinitionParserDelegate delegate )  { 
	// Parse the default label and return BeanDefinitionHolder 
	BeanDefinitionHolder bdHolder = delegate . parseBeanDefinitionElement ( ele ) ; 
	// If not empty, parse custom label 
	if  ( bdHolder != null )  { 
		// <2021-03-06 05:50>
		bdHolder = delegate . decorateBeanDefinitionIfRequired ( ele , bdHolder ) ; 
		try  { 
			// Register a BeanDefinition that has processed default tags + custom tags 
			BeanDefinitionReaderUtils . registerBeanDefinition ( bdHolder ,  getReaderContext ( ) . getRegistry ( ) ) ; 
		} 
		catch  ( BeanDefinitionStoreException ex )  { 
			getReaderContext ( ) . error ("Failed to register bean definition with name '"  + 
					bdHolder . getBeanName ( )  +  "'" , ele , ex ) ; 
		} 
		// triggers the registration completion event 
		getReaderContext ( ) . fireComponentRegistered ( new  BeanComponentDefinition ( bdHolder ) ) ; 
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

<2021-03-06 05:50>Register custom tags at, source code:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # decorateBeanDefinitionIfRequired ( org.w3c.dom.Element , org.springframework.beans.factory.config.BeanDefinitionHolder ) public BeanDefinitionHolder decorateBeanDefinitionRequired ( Element ele , BeanDefinitionHolder originalDef ) { return _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 
	 decorateBeanDefinitionIfRequired ( ele , originalDef , null ) ; 
}
  • 1
  • 2
  • 3
  • 4

continue:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # decorateBeanDefinitionIfRequired ( org.w3c.dom.Element , org.springframework.beans.factory.config.BeanDefinitionHolder , org.springframework.beans.factory.config.BeanDefinition ) public _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
BeanDefinitionHolder decorateBeanDefinitionIfRequired ( 
			Element ele , BeanDefinitionHolder originalDef ,  @Nullable BeanDefinition containingBd )  {
	
	BeanDefinitionHolder finalDefinition = originalDef ;

	// Get all attributes, loop through custom attributes 
	NamedNodeMap attributes = ele . getAttributes ( ) ; 
	for  ( int i =  0 ; i < attributes . getLength ( ) ; i ++ )  { 
		Node node = attributes . item ( i ) ; 
		finalDefinition =  decorateIfRequired ( node , finalDefinition , containingBd ) ;
	}

	// Get all child elements, loop through all child elements 
	NodeList children = ele . getChildNodes ( ) ; 
	for  ( int i =  0 ; i < children . getLength ( ) ; i ++ )  { 
		Node node = children . item ( i ) ; 
		if  ( node . getNodeType ( )  == Node . ELEMENT_NODE )  {
			// <2021-03-06 05:53> finalDefinition 
			= decorateIfRequired  ( node , finalDefinition , containingBd ) ; } 
		} 
	// 
	Return 🈶 BeanDefinitionHolder after custom attributes and custom elements are processed 
	return finalDefinition ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

<2021-03-06 05:53>Execute the decoration of custom tags, source code:

org . springframework . beans . factory . _ _ _
 _ _ _ _ 
			_ _ _ _  _ _ _  _ 
	_ 
	_ _  _ _ node ) ; 
	// Either the default namespace or a custom namespace 
	if  ( namespaceUri != null &&  !isDefaultNamespace ( namespaceUri ) )  { 
		// Get the NamespaceHandler that handles the corresponding label through the namespace 
		NamespaceHandler handler =  this . readerContext . getNamespaceHandlerResolver ( ) . resolve ( namespaceUri ) ; 
		// Only handle if there is a handler 
		if  ( handler != null )  { 
			// call The decorate method of the processor completes the decoration. In this method, we can complete our own decoration logic. Of course, this is just one of the options . 
			BeanDefinitionHolder decorated = 
					handler . decorate ( node , originalDef,  new  ParserContext ( this . readerContext ,  this , containingBd ) ) ; 
			// return 
			if  ( decorated != null )  { 
				return decorated ; 
			} 
		} 
		else  if  ( namespaceUri . startsWith ( "http://www. springframework.org/" ) )  { 
			error ( "Unable to locate Spring NamespaceHandler for XML schema namespace ["  + namespaceUri +  "]", node ) ; 
		} 
		else  { 
			// A custom namespace, not to be handled by Spring - maybe "xml:...". 
			if  ( logger . isDebugEnabled ( ) )  { 
				logger . debug ( "No Spring NamespaceHandler found for XML schema namespace ["  + namespaceUri +  "]" ) ; 
			} 
		} 
	} 
	// The execution here indicates that there is no decoration, and the original 
	return originalDef is returned ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

The custom tag parsed above exists as a sub-tag of the bean tag. If it is not a sub-tag of the bean tag but a tag of the same level as the bean tag, this custom tag parsing has not yet been analyzed. What happens next in spring? This is the case in parsing custom tags .

Tags: Analysis of spring parsing bean tag process

spring spring java

Related: Analysis of spring parsing bean tag process