spring加载xml文件异常解决方案记录

Spring版本: 5.3.x

问题描述

在测试Spring Bean工厂加载XML文件的时候,报出如下异常:

1
2
3
4
5
6
7
8
9
log复制代码Passed-in Resource [InputStream resource [resource loaded through InputStream]] contains an open stream: cannot determine validation mode automatically. Either pass in a Resource that is able to create fresh streams, or explicitly specify the validationMode on your XmlBeanDefinitionReader instance.
org.springframework.beans.factory.BeanDefinitionStoreException: Passed-in Resource [InputStream resource [resource loaded through InputStream]] contains an open stream: cannot determine validation mode automatically. Either pass in a Resource that is able to create fresh streams, or explicitly specify the validationMode on your XmlBeanDefinitionReader instance.
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.detectValidationMode(XmlBeanDefinitionReader.java:468)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.getValidationModeForResource(XmlBeanDefinitionReader.java:449)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadDocument(XmlBeanDefinitionReader.java:433)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:338)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReaderTests.testSimpleBeanLoad(XmlBeanDefinitionReaderTests.java:70)

先贴出源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
xml复制代码@Test
public void testSimpleBeanLoad() {
//新版本XML的Bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//获取配置文件
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
//加载配置文件到Bean工厂
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource);
//获取其中的一个Bean配置
TestBean bean = factory.getBean("rod", TestBean.class);
assertThat(bean).isNotNull();
assertThat(bean.getName()).isNotNull();
}

问题分析

  • 直接原因:
    org.springframework.beans.factory.xml.XmlBeanDefinitionReader#detectValidationMode方法进行验证模式检测时,首先会检查ResourceidOpen(),如果返回的是 true, 则会抛出上述的BeanDefinitionStoreException异常。
1
2
3
4
5
6
7
8
9
10
java复制代码protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException(
"Passed-in Resource [" + resource + "] contains an open stream: " +
"cannot determine validation mode automatically. Either pass in a Resource " +
"that is able to create fresh streams, or explicitly specify the validationMode " +
"on your XmlBeanDefinitionReader instance.");
}
//...
}
  • 根本原因
    isOpen()的值是Resource实现本身写定的,我们使用的InputStreamResource刚好定义的是true, 故而报出此异常。
1
2
3
java复制代码public boolean isOpen() {
return true;
}

解决方案

其实问题的解决方案在InputStreamResource中已经注释出来了。

1
2
3
4
5
scss复制代码给定InputStream Resource实现。
仅当没有其他特定的Resource实现适用时才应使用。
特别是,在可能的情况下,更喜欢ByteArrayResource或任何基于文件的Resource实现。
与其他Resource实现相反,这是一个已经打开的资源的描述符 - 因此从isOpen()返回true 。
如果需要将资源描述符保留在某处,或者需要多次从流中读取,请不要使用InputStreamResource 。

image.png

而相关的实现有很多, 如下列出的:

1
2
3
4
5
6
7
8
markdown复制代码* WritableResource
* ContextResource
* UrlResource
* FileUrlResource
* FileSystemResource
* ClassPathResource
* ByteArrayResource
* InputStreamResource

最终的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
scss复制代码@Test
public void testSimpleBeanLoad() {
//新版本XML的Bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//获取配置文件
Resource resource = new FileSystemResource(getClass().getResource("test.xml").getPath());
//加载配置文件到Bean工厂
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource);
//获取其中的一个Bean配置
TestBean bean = factory.getBean("multiAliased", TestBean.class);
assertThat(bean).isNotNull();
assertThat(bean.getName()).isNotNull();
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%