3.2alias标签解析 ~ 3.4嵌入式Beans标签解析
3.2alias标签解析
终于解析完了默认标签中对bean标签的解析,解析来对配置文件中import标签、alias标签、beans标签进行分析。
alias标签,别名标签。在配置文件中,有两种声明别名的方式。
1)bean标签的name属性(name支持配置多个,可以用,;分隔)
<bean id="testBean" name="testBean1,testBean2" class="TestBean" />
2)alias标签(alias不支持配置多个)
<bean id="testBean" class="TestBean" />
<alias name="testBean" alias="testBean1" />
<alias name="testBean" alias="testBean2" />
DefaultBeanDefinitionDocumentReader private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { //对import标签处理 importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { //对alias标签处理 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { //对bean标签处理 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse //对beans标签处理 doRegisterBeanDefinitions(ele); } } protected void processAliasRegistration(Element ele) { //获取beanName String name = ele.getAttribute(NAME_ATTRIBUTE); //获取alias String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { //注册别名 getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } //通知监听器 getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } } //SimpleAliasRegistry public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { //如果beanName与alias相同的话不记录alias,并删除对应的alias if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } //如果alias不允许被覆盖则抛出异常 if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } //当A->B存在时,若再次出现A->C->B时候则会抛出异常 //当beanName A 指定 别名 B时候 checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
这里没什么特别的。
注册简单来说就是把别名、beanName放入一个Map<String, String> aliasMap = new ConcurrentHashMap<>(16) 中。key为别名,value为beanName。
3.3Import标签的解析
解析import标签做的就是获取resource中的配置文件,然后转成Document,Document转成BeanDefinition......
import标签的好处:简化配置后期维护复杂度,并使配置模块化,易于管理。
import标签配置
<beans>
<import resource="applicationProperties1.xml" />
<import resource="applicationProperties2.xml" />
</beans>
DefaultBeanDefinitionDocumentReader protected void importBeanDefinitionResource(Element ele) { //获取resource属性 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); //如果不存在resource属性则不做处理 if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } // Resolve system properties: e.g. "${user.dir}" //解析系统属性,格式如${user.dir} location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<>(4); // Discover whether the location is an absolute or relative URI boolean absoluteLocation = false; try { //判断localtion是绝对路径还是相对路径 absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" } // Absolute or relative? //如果是绝对路径直接根据地址加载对应的配置文件 if (absoluteLocation) { try { int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isTraceEnabled()) { logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // No URL -> considering resource location as relative to the current file. //如果是相对路径则根据相对路径算出绝对路径 try { int importCount; //Resource存在多个子实现类,如VfsResource,FileSystemResource //而每一个resource的createRelative方式实现都不一样,所以这里先使用子类的方法尝试解析 Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { //如果解析不成,则使用默认解析器解析 String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isTraceEnabled()) { logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[0]); //解析后通知监听器做相应处理 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }
大致逻辑:
1)获取resource属性所表示的路径
2)解析路径中的系统属性,格式如“${user.dir}”
3)判定location是否绝对路径还是相对路径
4)如果是绝对路径则递归调用bean的解析过程,进行另一次的解析。这里的loadBeanDefinitions(relativeResource)其实就是从第2章开始的解析又走了一次,把relativeResource这个配置文件中的配置解析成BeanDefinition存起来........
5)如果是相对路径则计算出绝对路径并进行解析
6)通知监听器,解析完成。
3.4嵌入式beans标签解析
嵌入式beans标签,非常类似于import标签所提供的功能。将beans转换为Document,Document转成BeanDefinition......
<beans xmlns="http://www.springframework.org/schema/beas">
<bean id="test" class="Test" />
<beans></beans>
</beans>

浙公网安备 33010602011771号