봄에는 항아리 내부의 파일이 보이지 않습니다.


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

루트에는 다음과 같이 내 spring-context.xml에서 참조되는 my.config라는 파일이 있습니다.

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

항아리를 실행하면 해당 특정 파일의로드를 제외한 모든 것이 잘 보입니다.

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에서로드됩니다.
  • 스프링 컨텍스트가로드 됨 (new 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()not 을 사용하고 있는지 확인하십시오 resource.getFile().


1
그들은 같은 항아리에 있지만 동일한 결과로 솔루션을 시도했습니다. java.io.FileNotFoundException : 클래스 경로 리소스 [classpath * : my.config] 존재하지 않기 때문에 URL로 확인할 수 없습니다
BTakacs

14
다시 살펴보면 일부 호출 코드 (아마도 BeanConfigurationFactoryBean)가 java.io.File을로드하려고합니다. file은 jar의 항목이 아닌 파일 시스템의 파일을 참조합니다. 호출 코드는 jar에서로드하는 대신 resource.getInputStream을 사용해야합니다.
sbk

57
... 그리고 이것이 답입니다 ... 감사합니다! jar 내부에 resource.getFile ()을 사용하지 마십시오. :-)
BTakacs 2013

2
"왜?" 항아리 안에 getFile ()을 사용하지 않는 이유는 무엇입니까? 단순히 파일이 Jar 내부에 있으므로 "파일"이 jar 파일입니까 ??
RockMeetHardplace 2013

8
그게 다야. java.io.File은 디렉토리 구조에서 파일 시스템의 파일을 나타냅니다. Jar는 java.io.File입니다. 그러나 해당 파일 내의 모든 것은 java.io.File의 범위를 벗어납니다. 자바에 관한 한, 압축이 풀릴 때까지 jar 파일의 클래스는 단어 문서의 단어와 다르지 않습니다.
sbk

50

이 질문에 대한 답변이 이미 있다는 것을 알고 있습니다. 그러나 스프링 부트를 사용하는 사람들에게는이 링크가 도움이되었습니다-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의 범위를 벗어납니다. 자바에 관한 한, 압축이 풀릴 때까지 jar 파일의 클래스는 단어 문서의 단어와 다르지 않습니다.

getInputStream()대신 사용하는 이유를 이해하는 데 도움이 되었습니다. 이제 저에게 효과적입니다!

감사!


37

spring jar 패키지 ClassPathResource(filename).getFile()에서 예외를 발생시키는 new를 사용 합니다.

파일 시스템에 상주하지 않으므로 절대 파일 경로로 해석 할 수 없습니다. jar

그러나 new ClassPathResource(filename).getInputStream()를 사용 하면이 문제가 해결됩니다. 그 이유는 jar의 구성 파일이 운영 체제의 파일 트리에 존재하지 않으므로 getInputStream().


2

Tomcat6.x를 사용할 때 비슷한 문제가 있었고 내가 찾은 조언 중 아무것도 도움이되지 않았습니다. 결국 workTomcat의 폴더를 삭제 하고 문제가 사라졌습니다.

비논리적이지만 문서화 목적으로 ...


1

@sbk의 대답은 스프링 부트 환경 (@Value ( "$ {classpath * :})과는 별도로)에서 수행해야하는 방법입니다.하지만 내 시나리오에서는 독립 실행 형에서 실행하면 작동하지 않았습니다. 항아리 .. 내가 뭔가 잘못했을 수 있습니다.

하지만 이것은 이것을하는 또 다른 방법이 될 수 있습니다.

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

1

동일한 이름을 가진 파일이 두 개 이상 있고 하나는 기본 Spring Boot jar에 있고 다른 하나는 main fat jar 내부의 jar에 있기 때문에 더 복잡한 문제가 발생했습니다. 내 솔루션은 동일한 이름의 모든 리소스를 가져오고 그 후에 패키지 이름으로 필터링해야하는 리소스를 가져 왔습니다. 모든 파일을 가져 오려면 :

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

0

내 Spring 앱에서 리소스를 재귀 적으로로드하는 데 문제가 있었고 문제가 resource.getInputStream. 다음 config/myfilesjson파일 인 모든 파일을 재귀 적으로 읽는 방법을 보여주는 예 입니다.

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.