In the previous post, we just go through how code step to step and starting load spring beans.
For different node type, the related loading code are different.
BEAN_ELEMENT: ParseBeanDefinition
Example of xml
Firstly, the attribute “id” and “name” are retrieved from <bean/>. The name is used for alias purpose. The value could be “name1,name2;name3” with dilimiters {,;}
If there is Id assigned, the first name will used as bean id and the left be used as aliases.
Once the id and name are done, parseBeanDefinitionElement
A bean Definition is returned and add the bean name to bean definition holder.
We will go over all the logic later to see how will generate the bean name automatically when bean name is empty from xml file since most of time we will definitely define the bean id or name in spring xml configuration.
Now, just dig into parseBeanDefinitionElement (passing the bean name)
The code get the “parent” and “className” from xml.
See example about to how to parent xml attribute: by using parent attribute. The child bean inherits message2 property as is, and overrides message1 property and introduces one more property message
Create and set Bean Definition with parent and then override with new child properties.
autowire-candidate??
Parse Bean attribute:
1. scope
2. abstract
3. lazy-init
4. Autowire
5. Depends-on
6. Autowire-candiate
7. primary
8. init-method
9. destroy-method
10. Factory-method
11. factory-bean
parse Meta Elements
1. meta
2. Source of meta attribute
parseLookupOverrideSubElements
1. lookup-method: name, bean
parseReplacedMethodSubElements
1. replace-method: name, replace, arg-type, match
parseConstructorArgElements
1. constructor-arg: index, type, name, ref, value
2. parsePropertySubElement :support more value def (bean, ref, idref, value, null, array, list, set, props,)
parsePropertyElements
1. property
parseQualifierElements
1. qualifier:The bean with qualifier value "main" is wired with the constructor argument that is qualified with the same value.
Generate Bean Name: BeanDefinitionReaderUtils.generateBeanName
No Bean Class name:
Has parent: {parent name}$child
Factory bean name: {factory bean name}$created
Has bean class name: use given class name
After than, appending the hex string for inner bean ({bean name}#hexcode) or add the index for unique bean name ({beanName}#1)
For different node type, the related loading code are different.
BEAN_ELEMENT: ParseBeanDefinition
Example of xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<bean id="factoryReferencer" class="org.springframework.beans.factory.xml.DummyReferencer"> | |
<property name="testBean1"><ref bean="singletonFactory"/></property> | |
<property name="testBean2"><ref bean="singletonFactory"/></property> | |
</bean> |
BeanDefinitionParserDelegate.parseBeanDefinitionElement
The second parameter containingBean is used to parse a value, ref or collection sub-element of a property or constructor-arg element. Here we just parse the regular bean, just leave the value as null.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Nullable | |
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { | |
String id = ele.getAttribute(ID_ATTRIBUTE); | |
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); | |
List<String> aliases = new ArrayList<>(); | |
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.isTraceEnabled()) { | |
logger.trace("No XML 'id' specified - using '" + beanName + | |
"' as bean name and " + aliases + " as aliases"); | |
} | |
} | |
if (containingBean == null) { | |
checkNameUniqueness(beanName, aliases, ele); | |
} | |
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); | |
if (beanDefinition != null) { | |
if (!StringUtils.hasText(beanName)) { | |
try { | |
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, if still possible, | |
// if the generator returned the class name plus a suffix. | |
// This is expected for Spring 1.2/2.0 backwards 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.isTraceEnabled()) { | |
logger.trace("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; | |
} |
Firstly, the attribute “id” and “name” are retrieved from <bean/>. The name is used for alias purpose. The value could be “name1,name2;name3” with dilimiters {,;}
If there is Id assigned, the first name will used as bean id and the left be used as aliases.
Once the id and name are done, parseBeanDefinitionElement
A bean Definition is returned and add the bean name to bean definition holder.
We will go over all the logic later to see how will generate the bean name automatically when bean name is empty from xml file since most of time we will definitely define the bean id or name in spring xml configuration.
Now, just dig into parseBeanDefinitionElement (passing the bean name)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public AbstractBeanDefinition parseBeanDefinitionElement( | |
Element ele, String beanName, @Nullable BeanDefinition containingBean) { | |
this.parseState.push(new BeanEntry(beanName)); | |
String className = null; | |
if (ele.hasAttribute(CLASS_ATTRIBUTE)) { | |
className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); | |
} | |
String parent = null; | |
if (ele.hasAttribute(PARENT_ATTRIBUTE)) { | |
parent = ele.getAttribute(PARENT_ATTRIBUTE); | |
} | |
try { | |
AbstractBeanDefinition bd = createBeanDefinition(className, parent); | |
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); | |
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); | |
parseMetaElements(ele, bd); | |
parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); | |
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); | |
parseConstructorArgElements(ele, bd); | |
parsePropertyElements(ele, bd); | |
parseQualifierElements(ele, bd); | |
bd.setResource(this.readerContext.getResource()); | |
bd.setSource(extractSource(ele)); | |
return bd; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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-3.0.xsd"> | |
<bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"> | |
<property name = "message1" value = "Hello World!"/> | |
<property name = "message2" value = "Hello Second World!"/> | |
</bean> | |
<bean id ="helloIndia" class = "com.tutorialspoint.HelloIndia" parent = "helloWorld"> | |
<property name = "message1" value = "Hello India!"/> | |
<property name = "message3" value = "Namaste India!"/> | |
</bean> | |
</beans> |
See example about to how to parent xml attribute: by using parent attribute. The child bean inherits message2 property as is, and overrides message1 property and introduces one more property message
Create and set Bean Definition with parent and then override with new child properties.
autowire-candidate??
Parse Bean attribute:
1. scope
2. abstract
3. lazy-init
4. Autowire
5. Depends-on
6. Autowire-candiate
7. primary
8. init-method
9. destroy-method
10. Factory-method
11. factory-bean
parse Meta Elements
1. meta
2. Source of meta attribute
parseLookupOverrideSubElements
1. lookup-method: name, bean
parseReplacedMethodSubElements
1. replace-method: name, replace, arg-type, match
parseConstructorArgElements
1. constructor-arg: index, type, name, ref, value
2. parsePropertySubElement :support more value def (bean, ref, idref, value, null, array, list, set, props,)
parsePropertyElements
1. property
parseQualifierElements
1. qualifier:The bean with qualifier value "main" is wired with the constructor argument that is qualified with the same value.
Generate Bean Name: BeanDefinitionReaderUtils.generateBeanName
No Bean Class name:
Has parent: {parent name}$child
Factory bean name: {factory bean name}$created
Has bean class name: use given class name
After than, appending the hex string for inner bean ({bean name}#hexcode) or add the index for unique bean name ({beanName}#1)
Comments
Post a Comment