Spirng的xml配置中有两大类标签
一种是默认的:如
<bean id="" class=""/>
另一种是自定义的:如
<tx:annotion-driven>
进入parseDefaultElement()方法,可见分别对四种默认标签进行了处理(import,alias,bean,beans)。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
bean标签的解析与注册
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
首先进行元素的解析,进入parseBeanDefinitionElement()方法,
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//解析id属性
String id = ele.getAttribute("id");
//解析name属性
String nameAttr = ele.getAttribute("name");
//分割name属性
List<String> aliases = new ArrayList();
if(StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
//如果id不存在且别名集合不为空,那么把集合的第一个别名当作beanName
if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
beanName = (String)aliases.remove(0);
if(this.logger.isDebugEnabled()) {
this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
}
if(containingBean == null) {
this.checkNameUniqueness(beanName, aliases, ele);
}
//进一步解析其他所有属性并封装
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
if(beanDefinition != null) {
//如果beanName不存在 那么根据spring提供的命名规则生成beanName
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(this.logger.isDebugEnabled()) {
this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
}
我们进入
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
方法查看,这个方法对标签其他属性进行解析
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
//解析class属性
if(ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
try {
String parent = null;
//解析parent属性
if(ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
//创建承载属性的AbstractBeanDefinition,实际类型是GenericBeanDefinition
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
//接着解析bean的各种属性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
接着,我们进入这个parseBeanDefinitionAttributes方法,我们可以很清楚的看到这里解析了什么属性,这里就不一一解释了。
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
if(ele.hasAttribute("scope")) {
bd.setScope(ele.getAttribute("scope"));
} else if(containingBean != null) {
bd.setScope(containingBean.getScope());
}
if(ele.hasAttribute("abstract")) {
bd.setAbstract("true".equals(ele.getAttribute("abstract")));
}
String lazyInit = ele.getAttribute("lazy-init");
if("default".equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit("true".equals(lazyInit));
String autowire = ele.getAttribute("autowire");
bd.setAutowireMode(this.getAutowireMode(autowire));
String dependencyCheck = ele.getAttribute("dependency-check");
bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
String autowireCandidate;
if(ele.hasAttribute("depends-on")) {
autowireCandidate = ele.getAttribute("depends-on");
bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
}
autowireCandidate = ele.getAttribute("autowire-candidate");
String destroyMethodName;
if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) {
bd.setAutowireCandidate("true".equals(autowireCandidate));
} else {
destroyMethodName = this.defaults.getAutowireCandidates();
if(destroyMethodName != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
if(ele.hasAttribute("primary")) {
bd.setPrimary("true".equals(ele.getAttribute("primary")));
}
if(ele.hasAttribute("init-method")) {
destroyMethodName = ele.getAttribute("init-method");
if(!"".equals(destroyMethodName)) {
bd.setInitMethodName(destroyMethodName);
}
} else if(this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
if(ele.hasAttribute("destroy-method")) {
destroyMethodName = ele.getAttribute("destroy-method");
if(!"".equals(destroyMethodName)) {
bd.setDestroyMethodName(destroyMethodName);
}
} else if(this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
if(ele.hasAttribute("factory-method")) {
bd.setFactoryMethodName(ele.getAttribute("factory-method"));
}
if(ele.hasAttribute("factory-bean")) {
bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
}
return bd;
}
接着看之前的代码
//提取描述到bd
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
//解析元数据
this.parseMetaElements(ele, bd);
进入这个方法查看,元数据就是bean标签下的meta标签,这个标签包含两个属性,一个是key,一个是value。元数据相当于给类中对应的属性赋值。
<bean id="" class="">
<meta key="属性" value="值">
</bean>
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
//获取所有子节点
NodeList nl = ele.getChildNodes();
//遍历子节点,装配元数据,将元数据属性添加到原来的bd中
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(this.isCandidateElement(node) && this.nodeNameEquals(node, "meta")) {
Element metaElement = (Element)node;
String key = metaElement.getAttribute("key");
String value = metaElement.getAttribute("value");
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(this.extractSource(metaElement));
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
接着来看
//解析look-method属性
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
进入方法,look-method属性并不常用,能实现依赖的注入,或者说对象的插拔
<bean id="" class="">
<lookup-method name="这个类中的方法名,这方法能返回一个实例对象" bean="这个实例对象的bean的名称">
</bean>
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) {
Element ele = (Element)node;
//获取需要修饰的方法
String methodName = ele.getAttribute("name");
//获取配置的bean
String beanRef = ele.getAttribute("bean");
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(this.extractSource(ele));
添加到bd的MethodOverrides中
overrides.addOverride(override);
}
}
}
接着来看解析replaced-method属性
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
怎么用
<bean id="" class="">
<replaced-method name="该类中需要被重写或者说替换的方法名" replacer="进行替换的bean名称,这个类需要实现MethodReplacer方法">
</bean>
结果是替换类的方法会替换原来类的方法,实现的MethodReplacer的方法跟动态代理很像,所以我们可以猜想到这个方法替换是怎么实现的。
接着看这个标签解析
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) {
Element replacedMethodEle = (Element)node;
//获取旧方法名
String name = replacedMethodEle.getAttribute("name");
//新的替换方法
String callback = replacedMethodEle.getAttribute("replacer");
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type");
Iterator var11 = argTypeEles.iterator();
while(var11.hasNext()) {
Element argTypeEle = (Element)var11.next();
String match = argTypeEle.getAttribute("match");
match = StringUtils.hasText(match)?match:DomUtils.getTextValue(argTypeEle);
if(StringUtils.hasText(match)) {
replaceOverride.addTypeIdentifier(match);
}
}
replaceOverride.setSource(this.extractSource(replacedMethodEle));
//最后还是添加到bd的MethodOverrides中
overrides.addOverride(replaceOverride);
}
}
}
接着来看解析构造函数参数
this.parseConstructorArgElements(ele, bd);
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) {
this.parseConstructorArgElement((Element)node, bd);
}
}
}
//解析子元素property
this.parsePropertyElements(ele, bd);
//解析子元素qualifier
this.parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(this.extractSource(ele));
AbstractBeanDefinition var7 = bd;
return var7;
} catch (ClassNotFoundException var13) {
this.error("Bean class [" + className + "] not found", ele, var13);
} catch (NoClassDefFoundError var14) {
this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
} catch (Throwable var15) {
this.error("Unexpected failure during bean definition parsing", ele, var15);
} finally {
this.parseState.pop();
}
return null;
}
然后我们就得到了这个承载bean所有属性的GenericBeanDefinition,回到原来的解析bean的方法parseBeanDefinitionElement,我们可以看到接下来是如果没有检测到beanName,然后生成默认的beanName,然后将所有获取到的信息封装进BeanDefinitionHolder,最后返回。
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(this.logger.isDebugEnabled()) {
this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//将所有获取到的信息封装进BeanDefinitionHolder,然后返回
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
接着回到之前的processBeanDefinition方法,此时已经获取了BeanDefinitionHolder ,
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析元素封装进BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder != null) {
//如果存在自定义标签,继续解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
接着我们来看对自定义标签的解析,可是这个默认标签中的怎么会存在自定义类型的解析呢,其实之前说的默认和自定义是针对于Bean,而这里的自定义类型其实是属性。
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
return this.decorateBeanDefinitionIfRequired(ele, definitionHolder, (BeanDefinition)null);
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
NamedNodeMap attributes = ele.getAttributes();
//遍历所有属性,看看是否有用于修饰的属性
for(int i = 0; i < attributes.getLength(); ++i) {
Node node = attributes.item(i);
finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
}
NodeList children = ele.getChildNodes();
//遍历所有子节点,看看是否有需要修饰的子元素
for(int i = 0; i < children.getLength(); ++i) {
Node node = children.item(i);
if(node.getNodeType() == 1) {
finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
进入decorateIfRequired()方法
public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
//获取自定义标签的命名空间
String namespaceUri = this.getNamespaceURI(node);
//对非默认标签进行修饰
if(!this.isDefaultNamespace(namespaceUri)) {
//根据命名空间找到对应处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if(handler != null) {
//对元素进行修饰
return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
}
if(namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
} else if(this.logger.isDebugEnabled()) {
this.logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
return originalDef;
}
然后我们要注解已经解析完的BeanDefinition
try {
//将beanHolder进行注册 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
进入方法
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
//使用beanName作为bean的唯一标识进行注册
String beanName = definitionHolder.getBeanName();
//通过beanName注册BeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
registerBeanDefinition这是个接口方法,我们需要找到实体类。因为这个注册器是从上层传递进来的,所以我们要一直往回查找,最后找到这方法在DefaultListableBeanFactory类中实现
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if(beanDefinition instanceof AbstractBeanDefinition) {
try {
//注册前最后一次校验,主要检验beanDefintion中的methodOverrides时候与工厂方法并存,或者对应的方法不存在
((AbstractBeanDefinition)beanDefinition).validate();
} catch (BeanDefinitionValidationException var7) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var7);
}
}
Map var3 = this.beanDefinitionMap;
//beanDefinitionMap是全局变量,会存在并发访问,所以加锁
synchronized(this.beanDefinitionMap) {
//处理已经注册的BeanDefinition
BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
//如果对应的beanName已经注册并不允许覆盖,则抛出异常
if(oldBeanDefinition != null) {
if(!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
}
if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + " with a framework-generated bean definition ': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else if(this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else {
//记录beanName
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
//注册beanDefinition,相当于放在一个用beanName做键的map中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//重置beanName对应的缓存
this.resetBeanDefinition(beanName);
}
接下来就是注册所有的别名
String[] aliases = definitionHolder.getAliases();
if(aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String aliase = var4[var6];
//注册别名,相当于把别名当键,beanName当值,放在map中
registry.registerAlias(beanName, aliase);
}
}
}
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
//通知监听器解析及注册完成,开发人员需要对注册时间进行监听时,将逻辑处理写入监听器中,目前没有做任何处理
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
小结
经过以上分析,我们来汇总一下整个过程:
①首先是对元素进行解析,获取元素的属性,先是获取id再获取name,这个的最终目的是获取唯一标识beanName,如果id不存在,beanName用name的值,如果name也不存在就自动生成beanName。在次之前,会对元素进行进一步解析,创建BeanDefinition,将所有的属性封装进这个BeanDefinition。
②如果有自定义属性,那么解析自定义标签,对这个BeanDefinition进行修饰。
③解析完成,注册到容器中,将beanName作为键,BeanDefinition作为值存到map中,其实这个容器就是一个map。这个map存在于XmlBeanFactory所继承的DefaultListableBeanFactory中private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(64);
。然后又将别名和beanName进行关联存到map中。
④最后发出响应事件,通知事件监听器。
alias标签解析
别名实现的方式有好多种,在之前讲的bean的标签中
<bean name="aa,bb,c">
name属性用多个逗号分隔,也能实现别名,getBean("aa")或者bb,cc都能得到这个bean,如何实现已经在之前讲过了通过对别名和和beanName的映射。
当然还有一种方式实现别名
<alias name="bean的id或者说beanName" alias="aa,bb,cc">
aa,bb,cc都是bean的别名
进入processAliasRegistration方法
protected void processAliasRegistration(Element ele) {
//获取属性
String name = ele.getAttribute("name");
String alias = ele.getAttribute("alias");
boolean valid = true;
if(!StringUtils.hasText(name)) {
this.getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if(!StringUtils.hasText(alias)) {
this.getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if(valid) {
try {
//注册别名 this.getReaderContext().getRegistry().registerAlias(name, alias);
} catch (Exception var6) {
this.getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, var6);
}
//通知监听器 this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
}
}
import标签的解析
import标签可以导入另一个配置文件。
protected void importBeanDefinitionResource(Element ele) {
//获取resource属性
String location = ele.getAttribute("resource");
if(!StringUtils.hasText(location)) {
this.getReaderContext().error("Resource location must not be empty", ele);
} else {
//解析系统属性,如${user.dir}
location = this.environment.resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet(4);
boolean absoluteLocation = false;
try {
//判断是绝对URI还是相对URI
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
} catch (URISyntaxException var11) {
;
}
int importCount;
//如果是绝对URI直接根据地质加载对应配置文件
if(absoluteLocation) {
try {
importCount = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
} catch (BeanDefinitionStoreException var10) {
this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
}
} else {
try {
//如果是相对地址就根据相对对地址计算出绝对地址
Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
if(relativeResource.exists()) {
//进行解析
importCount = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
} else {
//如果解析不成功,则使用默认解析器进行解析
String baseLocation = this.getReaderContext().getResource().getURL().toString();
importCount = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if(this.logger.isDebugEnabled()) {
this.logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
} catch (IOException var8) {
this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
} catch (BeanDefinitionStoreException var9) {
this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
}
}
//解析后进行进行监听器激活
Resource[] actResArray = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
this.getReaderContext().fireImportProcessed(location, actResArray, this.extractSource(ele));
}
}
嵌入式beans标签解析
这个无非是递归调用对beans的解析