Java类加载器错误:原因:java.io.IOException:流已关闭

问题描述 投票:3回答:2

当我将Webapp部署到Tomcat时,我遇到一个奇怪的错误,因为我相信类加载器的问题。当我使用Jetty在本地运行Webapp时,该错误没有出现。似乎我的.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

这里是导致错误的行:

String s = ConfigProvider.getConfig().getString("test");

这里是ConfigProvider类。它基本上扫描正则表达式^.*\\.config\\.yml$的所有资源文件,将其转换为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 }

这是我的项目结构,标题为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是我从父pom文件(Foo/pom.xml)中获得的类。我从WAR模块(application)打包了一个Foo/application/target/application.war文件,并与Tomcat一起部署了它。以前,我的项目是单个模块项目,只有一个Foo模块与application模块相同。然后,我添加了一个client模块并将该项目转换为一个多模块项目,问题出现了。我认为这是因为多个模块使我的类加载器变得混乱。我已经花了很多时间尝试调试它,但是仍然没有找到任何地方。任何人都知道可能是什么原因,或者可以考虑尝试的可能方法?

[如果需要更多信息,请告诉我。

java maven tomcat stream classloader
2个回答
5
投票

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

还请确保.yml文件包含在.war文件中。一些构建系统对资源的处理方式与Java类文件不同。


0
投票

Bean类成员变量应与.yml文件密钥匹配,第二种选择是,可能会给您错误的文件路径。

© www.soinside.com 2019 - 2024. All rights reserved.