ClassLoader.getResourceAsStream()
私はそれが2つを開きInputStreams
、どれも閉じず、1つだけをクライアントに返すことを証明しようとします。私の論理は正しいですか?JDK ソースは jdk1.8.0_25 から選択されます
Spring ClassPathResource を間隔で使用して (元の質問)、プロパティ ファイルにアクセスClassLoader.getResourceAsStream
するために使用している、閉じられていないリソースの問題に遭遇しました。InputStream
調査の結果、それが通り抜けて、そのストリームを開いていることclassLoader.getResourceAsStream
がわかりましたURL
が、すでにそのストリームを開いています。のJDKソース:URL url = getResource(name);
URL url = getResource(name)
ClassLoader
public InputStream getResourceAsStream(String name) {
URL url = getResource(name); /* SILENTLY OPENS AND DON'T CLOSES STREAM */
try {
return url != null ? url.openStream() : null; /* SECOND OPEN !!! */
} catch (IOException e) {
return null;
}
}
そのように指定するとclose()
、InputStream
によって開かれたストリームのみが閉じられurl.openStream()
ます。JDK ソース:
public final InputStream openStream() throws java.io.IOException {
return openConnection().getInputStream();
}
問題は、JDK がストリームを静かに開き、URL url = getResource(name)
** 2 番目の(クライアントに返される) ストリーム** を作成するためにさらに使用される URL オブジェクトを取得することです。このメソッドのソースを見てください:
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name); <---- we end up calling that method
}
if (url == null) {
url = findResource(name);
}
return url;
}
そして今、開いたストリームを忘れるgetBootstrapResource(name)
瞬間に!:Resource
URL
Resource
private static URL getBootstrapResource(String name) {
URLClassPath ucp = getBootstrapClassPath();
Resource res = ucp.getResource(name); <---- OPENING STREAM [see further]
return res != null ? res.getURL() : null; <--- LOSING close() CAPABILITY
}
ucp.getResource(name);
リソースを開くのはなぜですか?その method: を見てみましょう。これは次のようにthis.getResource(var1, true);
委譲します:
public Resource getResource(String var1, boolean var2) {
if(DEBUG) {
System.err.println("URLClassPath.getResource(\"" + var1 + "\")");
}
URLClassPath.Loader var3;
for(int var4 = 0; (var3 = this.getLoader(var4)) != null; ++var4) {
Resource var5 = var3.getResource(var1, var2); <-------- OPENING STREAM
if(var5 != null) {
return var5;
}
}
return null;
}
Resource var5 = var3.getResource(var1, var2);
ストリームを開くのはなぜですか?さらに見てください:
Resource getResource(final String var1, boolean var2) {
final URL var3;
try {
var3 = new URL(this.base, ParseUtil.encodePath(var1, false));
} catch (MalformedURLException var7) {
throw new IllegalArgumentException("name");
}
final URLConnection var4;
try {
if(var2) {
URLClassPath.check(var3);
}
var4 = var3.openConnection(); <------------ OPENING STREAM
InputStream var5 = var4.getInputStream();
if(var4 instanceof JarURLConnection) {
JarURLConnection var6 = (JarURLConnection)var4;
this.jarfile = URLClassPath.JarLoader.checkJar(var6.getJarFile());
}
} catch (Exception var8) {
return null;
}
return new Resource() {
public String getName() {
return var1;
}
public URL getURL() {
return var3;
}
public URL getCodeSourceURL() {
return Loader.this.base;
}
public InputStream getInputStream() throws IOException {
return var4.getInputStream();
}
public int getContentLength() throws IOException {
return var4.getContentLength();
}
};
}
と が閉じられていないことを確認できopenConnection()
、getInputStream()
すべての呼び出しが戻っResource
てきてフォールバックすることがわかります。最終的には、閉じずにgetURL()
ラップされたメソッドのみを使用しています。そのオブジェクトを使用して別のジェットを開き、それをクライアントに返すだけですただし、最初のストリームが閉じられていない状態で終了します)。Resource
InputStream
URL
InputStream
では、ClassLaoder.getResourceAsStream はリソースのリークで壊れていますか?
実用的な側面: 私はブロックで使用getResourceAsStream
してtry-with-resources
いますが、まだ 30 秒ごとにファイル名がロードされている実稼働環境で、クローズされていないリソースの問題があります。close()
さらに、すべてのリソースはガベージ コレクションで閉じられます。これはファイル ストリームインfinalize()
メソッドと一致しています。