博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
import标签的解析
阅读量:4584 次
发布时间:2019-06-09

本文共 6500 字,大约阅读时间需要 21 分钟。

前言

  Spring默认标签有四种:bean、import、alias、beans,前面的文章已经讲述了bean标签的解析,这篇文章继续了解Spring中默认标签的解析—import标签的解析。

import标签的解析

  对于Spring配置文件的编写,我想,经历过庞大项目的人,都有那种恐惧的心理,太多的配置文件了,不过,分模块是大多数人能想到的方法,但是,怎么分模块,那就仁者见仁智者见智了。使用import可以达到这个效果,例如我们可以构造这样的Spring配置文件:

   spring.xml文件中使用import的方式导入其他模块配置文件,如果有配置需要修改直接修改相应配置文件即可,若有新的模块需要引入直接新增import即可,这样大大简化了配置后期维护的复杂度,同时也易于管理。

Spring是利用importBeanDefinitionResource()这个方法来解析import标签的:

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;        }        // 解析系统属性例如:"${user.dir}"        location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);        Set
actualResources = new LinkedHashSet<>(4); //判断location是绝对URI还是相对URI boolean absoluteLocation = false; try { 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*:" } // 如果是绝对URI 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 { // 如果是相对URI则根据相对地址计算出绝对地址 try { int importCount; //这里先使用Resource的子类尝试解析 Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { //子类解析不成功,则使用默认的解析器ResourcePatternResolver进行解析 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)); }

 配合上述代码的注释,整个import解析的过程比较的清晰,步骤大致如下:

(1)获取Resource属性所表示的路径。

(2)解析路径中的系统属性,格式如“${User.dir}”。

(3)判断location是绝对路径还是相对路径。

(4)如果是绝对路径则递归调用bean解析过程,进行另一次的解析。

(5)如果是相对路径则计算出绝对路径再进行解析。

(6)通知监听器,解析完成。

路径判断

上面解析import的代码是通过下面的这句代码来判断location是相对路径还是绝对路径的:

absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();

判断绝对路径的规则如下:

  ❤ 以classpath*:或者classpath: 开头为绝对路径;

  ❤ 能够通过该location构建出java.net.URL 为绝对路径;

  ❤ 根据location构造java.net.URI 判断调用 isAbsolute()判断是否为绝对路径;

绝对路径:

  如果location为绝对路径,则调用在AbstractBeanDefinitionReader中的loadBeanDefinitions()方法:

public int loadBeanDefinitions(String location, @Nullable Set
actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int count = loadBeanDefinitions(resources); if (actualResources != null) { Collections.addAll(actualResources, resources); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]"); } return count; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int count = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location [" + location + "]"); } return count; } }

整个逻辑比较简单,首先获取ResourceLoader,然后根据不同的ResourceLoader执行不同的逻辑,主要是可能存在多个Resource,但是最终都会回归到XmlBeanDefinitionReader.loadBeanDefinitions(),所以这是一个递归的过程。

相对路径:

  如果是相对路径则会根据相应的Resource计算出相应的绝对路径,然后根据该绝对路径构造一个Resource,若该Resource已经存在,则调用XmlBeanDefinitionReader.loadBeanDefinitions()进行BeanDefinition加载,否则构造一个绝对的location,调用AbstractBeanDefinitionReader.loadBeanDefinitions()方法,与绝对路径一样。

至此,import标签的解析完毕,整个过程清晰明了:获取Resource属性值,得到正确的资源路径,然后调用loadBeanDefinitions()方法进行递归的BeanDefinition加载。

参考:《Spring源码深度解析》 郝佳 编著: 

转载于:https://www.cnblogs.com/Joe-Go/p/10114726.html

你可能感兴趣的文章
如何让HTML的编写更具结构性
查看>>
在实际的运用中,我经常遇到需要对基础表的数据进行筛选后再进行行转列
查看>>
UVALive 6560 The Urge to Merge
查看>>
菜鸟简述Jquery中Ajax发送post请求及XML响应
查看>>
Codeforces Round #269 (Div. 2) D. MUH and Cube Walls KMP
查看>>
HDU 4251 The Famous ICPC Team Again 主席树
查看>>
POJ 2774 Long Long Message 后缀数组
查看>>
datagrid中设置编辑,删除列是否可以访问
查看>>
Linux下I/O复用 Select与Poll
查看>>
python全栈学习--day10(函数进阶)
查看>>
Android初学第19天
查看>>
Flask框架web开发
查看>>
LRU算法
查看>>
MongoDB 系列(一) C# 类似EF语法简单封装
查看>>
ios github网址
查看>>
Django 数据库操作之数据库连接
查看>>
写log
查看>>
Python基础 ----- 流程控制
查看>>
选择语言之switch case
查看>>
实现斐波那契神兔
查看>>