您的位置:首页 > 编程语言 > Java开发

Spring--解析默认标签

2018-02-09 17:01 417 查看
测试:

BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
TextService textService=(TextService)beanFactory.getBean("textService");
textService.sayHello();


配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
<!-- 新添加表时要添加 的位置 -->
<bean id="textService" class="com.test.service.TextService">
<meta key="msg" value="hello world"/>
</bean>
</beans>


1 在DefaultBeanDefinitionDocumentReader的方法parseBeanDefinitions中对于标签的解析分为默认标签的解析和自定义标签的解析。而默认标签与自定义标签的的区分是根据命名空间来进行判断的。具体代码如下

BeanDefinitionParserDelegate类
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
public boolean isDefaultNamespace(String namespaceUri) {
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
}


protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//默认标签的解析
parseDefaultElement(ele, delegate);
}
else {
//自定义标签的解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
//自定义标签的计息
delegate.parseCustomElement(root);
}
}


默认标签的解析分为import、alias、bean、beans;对于beans标签及配置文件的最高父标签,采用深度优先遍历的方式,再次进入parseBeanDefinitions方法中进入解析。

2 bean标签的解析:BeanDefinitionParserDelegate-》parseBeanDefinitionElement

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//如果没有给id赋值,则将第一个name的值赋给id。
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");
}
}
//对name和alias的值与已经解析完成后存于HashSet中的name的值进行比较,即唯一性比较,成功则添加到HashSet中。
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);
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;
}


当没有id和name是有一个创建beanName的逻辑,特整理如下。



public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {

String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}

String id = generatedBeanName;
if (isInnerBean) {
// Inner bean: generate identity hashcode suffix.
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// Top-level bean: use plain class name.
// Increase counter until the id is unique.
int counter = -1;
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
}
return id;
}


比如:beanName生成:com.test.service.UserService#0

对、、等子标签的解析,返回GenericBeanDefinition对象,对象中以属性的形式存储各个标签的信息。

BeanDefinitionParserDelegate-》parseBeanDefinitionElement

public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));

String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}

try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//创建一个GenericBeanDefinition对象,
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//设置各个属性的值。如class,是否懒加载lazyInit
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//加载各个meta源数据
//如:
<bean id="textService" class="com.test.service.TextService">
<meta key="" value=""/>
</bean>
parseMetaElements(ele, bd);
//解析lookup-method标签,      http://blog.csdn.net/btwangzhi/article/details/78165862 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replaced-method标签
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析<constructor-arg>标签
parseConstructorArgElements(ele, bd);
//解析property标签
parsePropertyElements(ele, bd);
//解析qualifier标签
parseQualifierElements(ele, bd);

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;
}


如上对一个标签进行了解析然后,生成BeanDefinitionHolder对象,构造器为id和包含了标签各种各样的属性值,还有别名。

2 alias标签的解析

alias标签解析基本就是获取name属性和alias属性的值进行环路检测,

应用场景为:

核心代码如下:

public boolean hasAlias(String name, String alias) {
for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
String registeredName = entry.getValue();
if (registeredName.equals(name)) {
String registeredAlias = entry.getKey();
return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias));
}
}
return false;
}


说明:比如A->B存在时,不允许出现A->C->B.

未完待续。。。

参考Spring源码深度解析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: