Resource resource =
new ClassPathResource("classpath:spring/application.xml");
1.资源加载
ClassPathResource 分析
spring 框架提供bean的加载机制,定义在xml中注入的bean将被创建。 通过构造方法 appalication.xml 资源加载 classPathResource -》Resource 其它方法 1. getPath 获取路径 2. getClassLoader 获取类加载器 3. exists 资源解析存在性 4. getInputStream 获取输入流 5. getURL 获取url 6. createRelative 创建相对资源路径 7. getDescription 获取clazz 类名 + path 信息
/**
* classpath 下资源加载
*/
public class ClassPathResource extends AbstractFileResolvingResource {
private final String path;
//jvm 类加载器
private ClassLoader classLoader;
private Class<?> clazz;
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
//整理classpath 路径 (.. // prefix 等)
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
StringUtils cleanPath(path) 源码解析
clanPath 是对path路径的一个简单处理。
/**
* 例1 classpath:spring/application.xml
* 例2 http://blog.csdn.net/csdn_ygy
*/
public static String cleanPath(String path) {
if (path == null) {
return null;
}
//WINDOWS_FOLDER_SEPARATOR = "\\" FOLDER_SEPARATOR = "/"
/**
* 效果等同于String.replaceAll (使用StringBuffer)
* 用StringBuilder效率更快
*/
String pathToUse=replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);
int prefixIndex=pathToUse.indexOf(":");
String prefix="";
if (prefixIndex != -1) {
prefix=pathToUse.substring(0, prefixIndex + 1); // classpath http
if (prefix.contains("/")) {
prefix="";
} else { // spring/application.xml /blog.csdn.net/csdn_ygy
pathToUse=pathToUse.substring(prefixIndex + 1);
}
}
if (pathToUse.startsWith(FOLDER_SEPARATOR)) {
prefix=prefix + FOLDER_SEPARATOR;
pathToUse=pathToUse.substring(1); // spring/application.xml blog.csdn.net/csdn_ygy
}
/**
* 以/ 切割 String用正则且步骤繁琐,
* 本方法采用Stringbuilder 效率较快 {"spring","application.xml"}
*/
String[] pathArray=delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);
List<String> pathElements=new LinkedList<>();
int tops=0;
for (int i=pathArray.length - 1; i >= 0; i--) {
String element=pathArray[i]; //application.xml
if (CURRENT_PATH.equals(element)) {
} else if (TOP_PATH.equals(element)) {
tops++;
} else {
if (tops > 0) {
// Merging path element with element corresponding to top path.
tops--;
} else {
// Normal path element found.
pathElements.add(0, element);
}
}
}
// Remaining top paths need to be retained.
for (int i=0; i < tops; i++) {
pathElements.add(0, TOP_PATH);
}
return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);
}
2.资源解析
XmlBeanFactory (已过时)
直接使用DefaultListableBeanFactory (主要是对bean 注册后的处理)以及XmlBeanDefinitionReader (资源文件读取 解析 及注册)
// 用于从xml中读取 beanDefinition
@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
//资源文件读取 解析 及注册
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//加载beanDefinition
this.reader.loadBeanDefinitions(resource);
}
}
2.1资源解析-xml验证
XmlValidationModeDetector 源码分析(获取xml 后 ,对xml 约束文件解读 ,进行验证)
// 1 auto 2 dtd 3 xsd(schema) : xml 验证模式
public int detectValidationMode(InputStream inputStream) throws IOException {
// Peek into the file to look for DOCTYPE.
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false; //是否是dtd
String content;
while ((content = reader.readLine()) != null) {
// 判断是否为注释 <-- 注释设置 true "<-- xxxxxxxx" => xxxxxxxxxxxxx
content = consumeCommentTokens(content);
//如果读取的是注释 或者空则跳过
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) { //dtd 标志
isDtdValidated = true;
break;
}
if (hasOpeningTag(content)) { //是否含有 <
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD); //dtd 或者xsd(schema)
}
catch (CharConversionException ex) {
// Choked on some character encoding...
// Leave the decision up to the caller.
return VALIDATION_AUTO; //采取自动
}
finally {
reader.close(); //关闭资源
}
}
2.2资源解析-解析为document
DefaultDocumentLoader源码分析
//xml -》 document -》 bean
@Override // 资源 对象解析器 错误处理器 xml验证 xml命名空间 //由resourceLoader =》 获取
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
// 命名空间 和 验证模式(dtd xsd) -》 DocumentBuilderFactory
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
2.3资源解析-beandefinition 注册
XmlBeanDefinitionReader 分析(资源文件读取 解析 及注册)
**
* 资源文件读取 解析 及注册
*/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
//1.从xml中加载 beandefinition 返回注册的beandefinition 数量
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//通过属性记录已经加载过的资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取资源输入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//1.DocumentLoader 转化、解析document
//2.新建 BeanDefinitionDocumentReader (//定义读取document 并注册beandefinition功能)
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close(); //关闭资源
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//移除资源
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
}
//注册beandefinition 个数
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount(); //已加载bean 个数
//加载及注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//此次注册个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}