La lima all'interno del barattolo non è visibile per la primavera


103

Tutti

Ho creato un file jar con il seguente MANIFEST.MF all'interno:

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

Nella sua radice c'è un file chiamato my.config a cui si fa riferimento nel mio spring-context.xml in questo modo:

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

Se eseguo il jar, tutto sembra a posto tranne il caricamento di quel file specifico:

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
  • le classi vengono caricate dall'interno del vaso
  • spring e altre dipendenze vengono caricate da jar separati
  • viene caricato il contesto spring (new ClassPathXmlApplicationContext ("spring-context / applicationContext.xml"))
  • my.properties viene caricato in PropertyPlaceholderConfigurer ("classpath: my.properties")
  • se metto il mio file .config fuori dal file system e cambio l'URL della risorsa in 'file:', sembra che tutto vada bene ...

Qualche consiglio?

Risposte:


211

Se i tuoi file spring-context.xml e my.config sono in barattoli diversi, allora dovrai usare classpath*:my.config?

Maggiori info qui

Inoltre, assicurati di utilizzare resource.getInputStream()not resource.getFile()quando carichi da un file jar.


1
Sono nello stesso jar, ma ho provato la tua soluzione con lo stesso risultato: java.io.FileNotFoundException: la risorsa del percorso di classe [classpath *: my.config] non può essere risolta in URL perché non esiste
BTakacs

14
Guardando di nuovo, parte del codice chiamante (possibilmente BeanConfigurationFactoryBean) sta tentando di caricare un java.io.File. File si riferisce ai file sul filesystem, che le voci in un jar non lo sono. Il codice chiamante dovrebbe utilizzare resource.getInputStream invece per caricare un jar.
sbk

57
... e QUESTA è la risposta ... Grazie! All'interno di un jar non utilizzare resource.getFile () :-)
BTakacs

2
c'è qualche possibilità che ci sia un "perché?" dietro a non usare getFile () all'interno di un vaso? È semplicemente che il file si trova all'interno del Jar e quindi il "file" è il file jar ??
RockMeetHardplace

8
Questo è tutto. Un java.io.File rappresenta un file sul file system, in una struttura di directory. Il Jar è un java.io.File. Ma qualsiasi cosa all'interno di quel file è oltre la portata di java.io.File. Per quanto riguarda java, fino a quando non viene decompresso, una classe nel file jar non è diversa da una parola in un documento word.
sbk

50

So che questa domanda ha già avuto risposta. Tuttavia, per coloro che utilizzano lo spring boot, questo collegamento mi ha aiutato: https://smarterco.de/java-load-file-classpath-spring-boot/

Tuttavia, resourceLoader.getResource("classpath:file.txt").getFile();stava causando questo problema e il commento di sbk:

Questo è tutto. Un java.io.File rappresenta un file sul file system, in una struttura di directory. Il Jar è un java.io.File. Ma qualsiasi cosa all'interno di quel file è oltre la portata di java.io.File. Per quanto riguarda java, fino a quando non viene decompresso, una classe nel file jar non è diversa da una parola in un documento word.

mi ha aiutato a capire perché usare getInputStream()invece. Per me adesso funziona!

Grazie!


37

Nel pacchetto del vaso primaverile, utilizzo new ClassPathResource(filename).getFile(), che genera l'eccezione:

non può essere risolto in un percorso file assoluto perché non risiede nel file system: jar

Ma l'utilizzo di new ClassPathResource(filename).getInputStream()risolverà questo problema. Il motivo è che il file di configurazione nel jar non esiste nell'albero dei file del sistema operativo, quindi deve essere utilizzato getInputStream().


2

Ho avuto un problema simile durante l'utilizzo di Tomcat6.x e nessuno dei consigli che ho trovato mi è stato d'aiuto. Alla fine ho cancellatowork cartella (di Tomcat) e il problema è sparito.

So che è illogico ma a scopo di documentazione ...


1

La risposta di @sbk è il modo in cui dovremmo farlo nell'ambiente spring-boot (a parte @Value ("$ {classpath *:})), secondo me. Ma nel mio scenario non funzionava se l'esecuzione da standalone jar ... forse ho fatto qualcosa di sbagliato.

Ma questo può essere un altro modo per farlo,

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

1

Stavo riscontrando un problema più complesso perché ho più di un file con lo stesso nome, uno si trova nel barattolo principale di Spring Boot e altri sono in barattoli all'interno del barattolo grasso principale. La mia soluzione era ottenere tutte le risorse con lo stesso nome e successivamente ottenere quella che avevo bisogno di filtrare per nome del pacchetto. Per ottenere tutti i file:

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

0

Ho riscontrato un problema durante il caricamento ricorsivo delle risorse nella mia app Spring e ho scoperto che il problema era che avrei dovuto utilizzare resource.getInputStream. Ecco un esempio che mostra come leggere in modo ricorsivo tutti i file config/myfilesche sono jsonfile.

Esempio.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;
  }
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.