Java 类加载器错误:由:java.io.IOException: Stream closed
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21567374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java class loader bug: Caused by: java.io.IOException: Stream closed
提问by Popcorn
I'm getting a strange bug regarding I believe class loader issues when I deploy my webapp to Tomcat. The bug doesn't appear when I run my webapp locally using Jetty. It seems like my input streams for my .yml resource files are being closed for some reason when they shouldn't be. This bug first appeared when I tried to convert my single module project into a multi module project. Before that, it was working fine on Tomcat using the exact same code:
当我将我的 web 应用程序部署到 Tomcat 时,我遇到了一个关于我相信类加载器问题的奇怪错误。当我使用 Jetty 在本地运行我的 web 应用程序时,该错误不会出现。似乎我的 .yml 资源文件的输入流由于某种原因在不应该关闭的情况下被关闭。当我尝试将我的单模块项目转换为多模块项目时,这个错误首先出现。在此之前,它使用完全相同的代码在 Tomcat 上运行良好:
Caused by: org.yaml.snakeyaml.error.YAMLException: java.io.IOException: Stream closed
at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:200)
at org.yaml.snakeyaml.reader.StreamReader.<init>(StreamReader.java:60)
at org.yaml.snakeyaml.Yaml.load(Yaml.java:412)
at com.config.ConfigProvider.<init>(ConfigProvider.java:20)
... 49 more
Caused by: java.io.IOException: Stream closed
at java.io.PushbackInputStream.ensureOpen(PushbackInputStream.java:57)
at java.io.PushbackInputStream.read(PushbackInputStream.java:149)
at org.yaml.snakeyaml.reader.UnicodeReader.init(UnicodeReader.java:90)
at org.yaml.snakeyaml.reader.UnicodeReader.read(UnicodeReader.java:122)
at java.io.Reader.read(Reader.java:123)
at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:184)
... 55 more
Here's the line that causes the bug:
这是导致错误的行:
String s = ConfigProvider.getConfig().getString("test");
Here's the ConfigProvider
class. It basically scans for all resource files of regex ^.*\\.config\\.yml$
, converts it into a Map<String, Object>
, and combines all the obtained Map<String, Object>
into a single Map<String, Object>
:
这是ConfigProvider
课堂。它基本上扫描 regex 的所有资源文件^.*\\.config\\.yml$
,将其转换为 a Map<String, Object>
,并将所有获得的Map<String, Object>
合并为一个Map<String, Object>
:
1 public class ConfigProvider {
2 protected static final String CONFIG_PACKAGE = ConfigProvider.class.getPackage().getName();
3 protected static final Pattern CONFIG_PATH_REGEX = Pattern.compile("^.*\.config\.yml$");
4
5 private static final ConfigProvider INSTANCE = new ConfigProvider();
6 private Map<String, Object> configMap;
7
8 protected ConfigProvider() {
9 configMap = new HashMap<String, Object>();
10
11 Set<String> configPaths = new Reflections(CONFIG_PACKAGE,
12 new ResourcesScanner()).getResources(CONFIG_PATH_REGEX);
13
14 if (configPaths.isEmpty()) {
15 throw new RuntimeException("no config paths found");
16 }
17
18 for (String path : configPaths) {
19 InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
20 Map<String, Object> fullConfig = new Map<String, Object>((Map) new Yaml().load(inputStream));
21
22 try {
23 inputStream.close();
24 } catch (IOException e) {
25 throw new RuntimeException("error closing stream");
26 }
27
28 MapUtils.merge(configMap, fullConfig);
29 }
30 }
31
32 public static ConfigMap getConfig() {
33 return INSTANCE.configMap;
34 }
35 }
Here's my project structure, titled Foo:
这是我的项目结构,标题为 Foo:
- Foo (this is a module)
- .idea
- application (this is a module)
- src
- main
- java
- resources
- application.config.yml
- webapp
- test
- pom.xml
- client (this is a module)
- src
- main
- java
- resources
- client.config.yml
- webapp
- test
- pom.xml
- pom.xml
ConfigProvider
is a class I get from my parent pom file (Foo/pom.xml
). I package a WAR
file from the application
module (Foo/application/target/application.war
), and deploy it with Tomcat. Previously, my project was a single module project with just a Foo
module being identical to application
module. Then I added a client
module and converted the project into a multi module project, and the problem has showed up. I think it's because my class loader is getting messed up due to the multiple modules. I've spent a lot of time trying to debug this and still haven't gotten anywhere. Anyone know what could be the cause, or can think of possible things to try?
ConfigProvider
是我从父 pom 文件 ( Foo/pom.xml
)获得的类。我WAR
从application
模块 ( Foo/application/target/application.war
) 中打包了一个文件,并使用 Tomcat 进行部署。以前,我的项目是一个单模块项目,只有一个Foo
模块与application
模块相同。然后我添加了一个client
模块,将项目转换为多模块项目,问题就出现了。我认为这是因为我的类加载器由于多个模块而变得一团糟。我花了很多时间试图调试这个,但仍然没有得到任何结果。任何人都知道可能是什么原因,或者可以想到可能的尝试?
Please let me know if you need more info.
如果您需要更多信息,请告诉我。
采纳答案by David Levesque
According to this post, that exception could mean that the .yml
file is simply not found. Since you changed your project structure, it is possible that the logic used to build the configPaths
needs to be modified for the new structure. Did you try to log the content of configPaths
to see if the paths are correct for the new structure?
根据这篇文章,该异常可能意味着.yml
根本找不到该文件。由于您更改了项目结构,因此可能configPaths
需要针对新结构修改用于构建的逻辑。您是否尝试记录 的内容configPaths
以查看新结构的路径是否正确?
Also make sure that the .yml
files are included in the .war
file. Some build systems handle resources differently than java class files.
还要确保.yml
文件包含在.war
文件中。某些构建系统处理资源的方式与 Java 类文件不同。
回答by Adarsh Anand
Bean class member variable should match with .yml file keys and second option is there might be chances that you might be giving wrong file path.
Bean 类成员变量应与 .yml 文件键匹配,第二个选项是您可能会提供错误的文件路径。