本文介绍了Java类加载器错误:由以下原因引起:java.io.IOException:流已关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我将Webapp部署到Tomcat时,我遇到一个奇怪的错误,即我认为类加载器存在问题.当我使用Jetty在本地运行Webapp时,该错误没有出现.似乎我的.yml资源文件的输入流由于某些原因而被关闭,而不应这样做.当我尝试将单模块项目转换为多模块项目时,首次出现此错误.在此之前,它使用完全相同的代码在Tomcat上运行良好:

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:

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");

这是ConfigProvider类.它基本上扫描正则表达式^.*\\.config\\.yml$的所有资源文件,将其转换为Map<String, Object>,并将所有获得的Map<String, Object>组合为单个Map<String, Object>:

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>:

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:

Here's my project structure, titled 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)获得的类.我从application模块(Foo/application/target/application.war)打包了一个WAR文件,并与Tomcat一起部署了它.以前,我的项目是单个模块项目,只有一个Foo模块与application模块相同.然后,我添加了一个client模块并将该项目转换为一个多模块项目,问题出现了.我认为这是因为多个模块使我的类加载器变得一团糟.我已经花了很多时间尝试调试它,但仍然没到任何地方.任何人都知道可能是什么原因,或者可以想到可以尝试的事情吗?

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?

如果您需要更多信息,请告诉我.

Please let me know if you need more info.

推荐答案

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

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?

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

Also make sure that the .yml files are included in the .war file. Some build systems handle resources differently than java class files.

这篇关于Java类加载器错误:由以下原因引起:java.io.IOException:流已关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-12 07:08