jar内のファイルは春には表示されません


103

すべて

内部に次のMANIFEST.MFを含むjarファイルを作成しました。

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_25-b06 (Sun Microsystems Inc.)
Main-Class: my.Main
Class-Path: . lib/spring-core-3.2.0.M2.jar lib/spring-beans-3.2.0.M2.jar

ルートにはmy.configというファイルがあり、これは次のようにspring-context.xmlで参照されます。

<bean id="..." class="...">
    <property name="resource" value="classpath:my.config" />
</bean>

jarを実行すると、その特定のファイルのロードを除いて、すべてが正常に見えます。

Caused by: java.io.FileNotFoundException: class path resource [my.config] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/work/my.jar!/my.config
        at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:205)
    at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:32)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:1)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    ... 22 more
  • クラスはjar内からロードされます
  • 春と他の依存関係は別々のjarからロードされます
  • 春のコンテキストが読み込まれます(新しいClassPathXmlApplicationContext( "spring-context / applicationContext.xml"))
  • my.propertiesがPropertyPlaceholderConfigurerにロードされます( "classpath:my.properties")
  • .configファイルをファイルシステムの外に置き、リソースのURLを 'file:'に変更すると、すべてが問題ないようです...

任意のヒント?

回答:


211

spring-context.xmlファイルとmy.configファイルが異なるjarにある場合は、classpath*:my.config

詳細はこちら

また、jarファイル内からロードする場合は使用しresource.getInputStream()ないでくださいresource.getFile()


1
それらは同じjarにありますが、同じ結果でソリューションを試しました:java.io.FileNotFoundException:クラスパスリソース[classpath *:my.config]が存在しないため、URLに解決できません
BTakacs

14
もう一度見ると、呼び出しコードの一部(おそらくBeanConfigurationFactoryBean)がjava.io.Fileをロードしようとしています。ファイルは、ファイルシステム上のファイルを指しますが、jar内のエントリはそうではありません。呼び出しコードは、jarからロードする代わりに、resource.getInputStreamを使用する必要があります。
sbk 2013

57
...そしてこれが答えです...ありがとう!jar内ではresource.getFile()を使用しないでください:-)
BTakacs

2
「なぜ?」がある可能性があります jar内でgetFile()を使用しないのはなぜですか?それは単にファイルがjarの中にあり、したがって「ファイル」がjarファイルであることだけですか?
RockMeetHardplace 2013

8
それでおしまい。java.io.Fileは、ファイルシステム上のファイルをディレクトリ構造で表します。Jarはjava.io.Fileです。しかし、そのファイル内のすべてはjava.io.Fileの範囲を超えています。javaに関する限り、圧縮解除されるまで、jarファイル内のクラスはワードドキュメント内のワードと同じです。
sbk 2013

50

この質問には既に回答済みです。ただし、Spring Bootを使用している人にとっては、このリンクが役に立ちました-https://smarterco.de/java-load-file-classpath-spring-boot/

しかし、これresourceLoader.getResource("classpath:file.txt").getFile();がこの問題とsbkのコメントを引き起こしていました:

それでおしまい。java.io.Fileは、ファイルシステム上のファイルをディレクトリ構造で表します。Jarはjava.io.Fileです。しかし、そのファイル内のすべてはjava.io.Fileの範囲を超えています。javaに関する限り、圧縮解除されるまで、jarファイル内のクラスはワードドキュメント内のワードと同じです。

getInputStream()代わりに使用する理由を理解するのに役立ちました。今はうまくいきます!

ありがとう!


37

Spring jarパッケージClassPathResource(filename).getFile()では、例外をスローするnewを使用します。

ファイルシステムに存在しないため、絶対ファイルパスに解決できません:jar

しかし、new ClassPathResource(filename).getInputStream()を使用すると、この問題は解決します。その理由は、jar内の構成ファイルがオペレーティングシステムのファイルツリーに存在しないため、を使用する必要があるためgetInputStream()です。


2

Tomcat6.xを使用しているときに同様の問題があり、私が見つけたアドバイスのどれも役に立たなかった。最後にwork(Tomcatの)フォルダーを削除し、問題は解消しました。

私はそれが非論理的であることを知っていますが、文書化の目的で...


1

私の意見では、@ sbkの答えは、スプリングブート環境で実行する方法(@Value( "$ {classpath *:})を除く)ですが、私のシナリオでは、スタンドアロンから実行すると機能しませんでしたjar ..私は何か間違ったことをしたかもしれません。

しかし、これはこれを行う別の方法になる可能性があります。

InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);

1

同じ名前のファイルが複数あるため、問題がさらに複雑になりました。1つはメインのSpring Boot jarにあり、他のファイルはメインのfat jar内のjarにあります。私の解決策は、同じ名前のすべてのリソースを取得し、その後、パッケージ名でフィルタリングする必要があるリソースを取得することでした。すべてのファイルを取得するには:

ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);

0

Springアプリでリソースを再帰的に読み込むときに問題が発生しましたが、問題はを使用する必要があることresource.getInputStreamでした。以下は、ファイルでconfig/myfilesあるすべてのファイルを再帰的に読み取る方法を示す例jsonです。

Example.java

private String myFilesResourceUrl = "config/myfiles/**/";
private String myFilesResourceExtension = "json";

ResourceLoader rl = new ResourceLoader();

// Recursively get resources that match. 
// Big note: If you decide to iterate over these, 
// use resource.GetResourceAsStream to load the contents
// or use the `readFileResource` of the ResourceLoader class.
Resource[] resources = rl.getResourcesInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);

// Recursively get resource and their contents that match. 
// This loads all the files into memory, so maybe use the same approach 
// as this method, if need be.
Map<Resource,String> contents = rl.getResourceContentsInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);

ResourceLoader.java

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.StreamUtils;

public class ResourceLoader {
  public Resource[] getResourcesInResourceFolder(String folder, String extension) {
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    try {
      String resourceUrl = folder + "/*." + extension;
      Resource[] resources = resolver.getResources(resourceUrl);
      return resources;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public String readResource(Resource resource) throws IOException {
    try (InputStream stream = resource.getInputStream()) {
      return StreamUtils.copyToString(stream, Charset.defaultCharset());
    }
  }

  public Map<Resource, String> getResourceContentsInResourceFolder(
      String folder, String extension) {
    Resource[] resources = getResourcesInResourceFolder(folder, extension);

    HashMap<Resource, String> result = new HashMap<>();
    for (var resource : resources) {
      try {
        String contents = readResource(resource);
        result.put(resource, contents);
      } catch (IOException e) {
        throw new RuntimeException("Could not load resource=" + resource + ", e=" + e);
      }
    }
    return result;
  }
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.