Ci sono sottili differenze su come fileName
viene interpretato il passaggio. Fondamentalmente, hai 2 metodi diversi: ClassLoader.getResourceAsStream()
e Class.getResourceAsStream()
. Questi due metodi individueranno la risorsa in modo diverso.
In Class.getResourceAsStream(path)
, il percorso viene interpretato come un percorso locale al pacchetto della classe da cui lo si chiama. Per esempio chiamata, String.getResourceAsStream("myfile.txt")
sarà cercare un file nel classpath al seguente indirizzo: "java/lang/myfile.txt"
. Se il tuo percorso inizia con un /
, allora sarà considerato un percorso assoluto e inizierà la ricerca dalla radice del percorso di classe. Quindi la chiamata String.getResourceAsStream("/myfile.txt")
esaminerà la seguente posizione nel percorso della classe ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
considererà tutti i percorsi come percorsi assoluti. Quindi chiamare String.getClassLoader().getResourceAsStream("myfile.txt")
e String.getClassLoader().getResourceAsStream("/myfile.txt")
saranno entrambi cercare un file nel classpath al seguente indirizzo: ./myfile.txt
.
Ogni volta che menziono una posizione in questo post, potrebbe essere una posizione nel tuo filesystem stesso o all'interno del file jar corrispondente, a seconda della classe e / o ClassLoader da cui stai caricando la risorsa.
Nel tuo caso, stai caricando la classe da un Application Server, quindi dovresti usare Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
invece di this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
funzionerà anche.
Leggi questo articolo per informazioni più dettagliate su quel particolare problema.
Avviso per gli utenti di Tomcat 7 e versioni precedenti
Una delle risposte a questa domanda afferma che la mia spiegazione sembra essere errata per Tomcat 7. Ho cercato di guardarmi intorno per capire perché sarebbe così.
Quindi ho esaminato il codice sorgente di Tomcat WebAppClassLoader
per diverse versioni di Tomcat. L'implementazione di findResource(String name)
(che è assolutamente responsabile della produzione dell'URL per la risorsa richiesta) è praticamente identica in Tomcat 6 e Tomcat 7, ma è diversa in Tomcat 8.
Nelle versioni 6 e 7, l'implementazione non tenta di normalizzare il nome della risorsa. Ciò significa che in queste versioni, classLoader.getResourceAsStream("/resource.txt")
potrebbe non produrre lo stesso risultato classLoader.getResourceAsStream("resource.txt")
dell'evento, anche se dovrebbe (dal momento che ciò che Javadoc specifica). [codice sorgente]
Nella versione 8, tuttavia, il nome della risorsa è normalizzato per garantire che la versione assoluta del nome della risorsa sia quella utilizzata. Pertanto, in Tomcat 8, le due chiamate sopra descritte dovrebbero sempre restituire lo stesso risultato. [codice sorgente]
Di conseguenza, devi fare molta attenzione quando usi ClassLoader.getResourceAsStream()
o Class.getResourceAsStream()
su versioni Tomcat precedenti alla 8. E devi anche tenere presente che in class.getResourceAsStream("/resource.txt")
realtà chiama classLoader.getResourceAsStream("resource.txt")
(il lead /
è privato).
getClass().getResourceAsStream("/myfile.txt")
si comporti diversamente dagetClassLoader().getResourceAsStream("/myfile.txt")
.