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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:24:03  来源:igfitidea点击:

Java class loader bug: Caused by: java.io.IOException: Stream closed

javamaventomcatstreamclassloader

提问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 ConfigProviderclass. 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

ConfigProvideris a class I get from my parent pom file (Foo/pom.xml). I package a WARfile from the applicationmodule (Foo/application/target/application.war), and deploy it with Tomcat. Previously, my project was a single module project with just a Foomodule being identical to applicationmodule. Then I added a clientmodule 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)获得的类。我WARapplication模块 ( 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 .ymlfile is simply not found. Since you changed your project structure, it is possible that the logic used to build the configPathsneeds to be modified for the new structure. Did you try to log the content of configPathsto see if the paths are correct for the new structure?

根据这篇文章,该异常可能意味着.yml根本找不到该文件。由于您更改了项目结构,因此可能configPaths需要针对新结构修改用于构建的逻辑。您是否尝试记录 的内容configPaths以查看新结构的路径是否正确?

Also make sure that the .ymlfiles are included in the .warfile. 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 文件键匹配,第二个选项是您可能会提供错误的文件路径。