2011-07-07 9 views
146

Me pregunto cuál es la diferencia entre Class.getResource() y ClassLoader.getResource()?¿Cuál es la diferencia entre Class.getResource() y ClassLoader.getResource()?

editar: Especialmente quiero saber si hay algún almacenamiento en caché involucrado en el nivel de archivo/directorio. Como en "¿los listados de directorios están almacenados en caché en la versión Class?"

yo sepa lo siguiente en esencia debería hacer lo mismo, pero no lo son:

getClass().getResource() 
getClass().getClassLoader().getResource() 

descubrí esto cuando jugando con algún código de generación de informes que crea un nuevo archivo en WEB-INF/classes/ desde un archivo existente en ese directorio . Al usar el método de Class, pude encontrar los archivos que estaban allí en la implementación usando getClass().getResource(), pero cuando traté de recuperar el archivo recién creado, recibí un objeto nulo. La navegación por el directorio muestra claramente que el nuevo archivo está allí. Los nombres de archivo fueron precedidos por una barra inclinada como en "/myFile.txt".

La versión ClassLoader de getResource() encontró el archivo generado. A partir de esta experiencia, parece que hay algún tipo de almacenamiento en caché de la lista de directorios en curso. Estoy en lo correcto, y si es así, ¿dónde está esto documentado?

Desde el API docs en Class.getResource()

encuentra un recurso con un nombre dado. Las reglas para buscando recursos asociados con una clase dada son implementadas por el cargador de clase de definición de la clase. Este método se delega en el cargador de clases de este objeto. Si este objeto era cargado por el cargador de clases de rutina de carga, el método delega en ClassLoader.getSystemResource (java.lang.String).

Para mí, esto dice "Class.getResource realmente está llamando a su propio cargador de clase getResource()". Lo cual sería lo mismo que hacer getClass().getClassLoader().getResource(). Pero obviamente no es así. ¿Podría alguien darme alguna información sobre este asunto?

Respuesta

3

Para responder a la pregunta de si hay alguna almacenamiento en caché pasando .

He investigado este punto más a fondo mediante la ejecución de una aplicación Java independiente que carga continuamente un archivo desde el disco utilizando el método getResourceAsStream ClassLoader. Pude editar el archivo y los cambios se reflejaron de inmediato, es decir, el archivo se volvió a cargar desde el disco sin almacenamiento en caché.

Sin embargo: Estoy trabajando en un proyecto con varios módulos maven y proyectos web que tienen dependencias entre ellos. Estoy usando IntelliJ como mi IDE para compilar y ejecutar proyectos web.

Me di cuenta de que lo anterior parecía no ser cierto, porque el archivo que estaba cargando se ha convertido en un contenedor y se ha implementado en el proyecto web dependiente. Solo me di cuenta de esto después de intentar cambiar el archivo en mi carpeta de destino, pero fue en vano. Esto hizo que pareciera que estaba pasando el almacenamiento en caché.

+0

Yo también usé Maven e IntelliJ, así que esta es la respuesta en un entorno que se acerca más al mío y tiene una explicación razonable para la pregunta n. ° 2. – oligofren

15

La primera llamada busca en relación con el archivo .class mientras que la última busca en relación con la raíz de la ruta de clase.

Para depurar problemas por el estilo, yo imprimir la URL:

System.out.println(getClass().getResource(getClass().getSimpleName() + ".class")); 
+2

I Creo que "classloader root" sería más preciso que "classpath root" - solo para ser selectivo. –

+4

Ambos pueden buscar "rutas absolutas" si el nombre del archivo está precedido por "/" – oligofren

+2

Interesante ... Estoy llegando a un caso donde getClass() .getResource ("/ someAbsPath") devuelve una URL en el tipo /path/to/mylib.jar!/someAbsPath y getClass(). getClassLoafer(). getResource ("/ someAbsPath") devuelve nulo ... Entonces " raíz de clase cargador "parece no ser una noción muy bien definida ... –

13

tenía que mirar hacia arriba en las especificaciones:

getResource

de clase() - documentación indica la diferencia:

Este método delegados de la llamada a su cargador de clases, después de hacer estos cambios en el nombre de recurso: si el nombre de recurso comienza con "/", es sin cambios ; de lo contrario, el nombre del paquete se antepone al nombre del recurso después de convertir "." a "/". Si este objeto fue cargado por el cargador de arranque, la llamada se delega a ClassLoader.getSystemResource.

+2

¿Tiene alguna información sobre si también almacena en caché la lista del directorio? Esta fue la principal diferencia entre los dos métodos cuando al buscar por primera vez un archivo de entrada, y luego crear un archivo usando eso en el mismo directorio. La versión Class no lo encontró, la versión ClassLoader lo hizo (ambas usando "/file.txt"). – oligofren

174

Class.getResource puede tomar un nombre de recurso "relativo", que se trata en relación con el paquete de la clase. Alternativamente, puede especificar un nombre de recurso "absoluto" utilizando una barra diagonal. Las rutas de recursos de ClassLoader siempre se consideran absolutas.

por lo que son básicamente equivalentes:

foo.bar.Baz.class.getResource("xyz.txt"); 
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt"); 

Y también lo son estos (pero que son diferentes de lo anterior :)

foo.bar.Baz.class.getResource("/data/xyz.txt"); 
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt"); 
+0

Buena respuesta con ejemplos claros. Aunque la publicación en realidad estaba destinada a obtener respuestas a dos preguntas, ahora veo que la segunda pregunta está oculta. No estoy seguro de cómo/debo actualizar la publicación para reflejar esto, pero lo que me gustaría saber en segundo lugar es este (siguiente comentario): – oligofren

+0

¿Hay algún tipo de almacenamiento en caché en la versión Class.getResource()? Lo que me hizo creer que esta es la generación de algunos informes de jaspe: Usamos getClass(). GetResource ("/ aDocument.jrxml") para obtener el archivo jasper xml. A continuación, se genera un archivo jaspe binario en el * mismo * directorio. getClass(). getResource ("/ aDocument.jasper") no puede encontrarlo, aunque puede encontrar documentos claramente en el mismo nivel (el archivo de entrada). Aquí es donde ClassLoader.getResource() resultó útil, ya que parece que no utiliza el almacenamiento en caché de la lista de directorios. Pero no puedo encontrar documentación sobre esto. – oligofren

+2

@oligofren: Hmm ... No esperaba * Class.getResource() para hacer ningún almacenamiento en caché allí ... –

8

Todas estas respuestas por aquí, así como las respuestas en this question, sugieren que la carga de las direcciones URL absolutas, como "/foo/bar.properties" tratado de la misma por class.getResourceAsStream(String) y class.getClassLoader().getResourceAsStream(String). Este NO es el caso, al menos no en mi configuración/versión de Tomcat (actualmente 7.0.40).

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works! 
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work! 

Lo sentimos, no tengo absolutamente ninguna explicación satisfactoria, pero supongo que Tomcat hace trucos sucios y su magia negro con los cargadores de clases y hacen que la diferencia. Siempre he usado class.getResourceAsStream(String) en el pasado y no he tenido ningún problema.

PS: También ha publicado esto sobre here

+0

Este comportamiento parece ser un error en Tomcat que se corrigió en la versión 8. Agregué un párrafo sobre eso en mi [respuesta sobre esta pregunta] (http://stackoverflow.com/questions/676250/different-ways-of- loading-a-file-as-an-entrytream/676273 # 676273) – LordOfThePigs

1

Traté de leer input1.txt que estaba dentro de uno de mis paquetes junto con la clase que estaba tratando de leerlo.

las siguientes obras:

String fileName = FileTransferClient.class.getResource("input1.txt").getPath(); 

System.out.println(fileName); 

BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName)); 

la parte más importante fue llamar getPath() si desea que el nombre de la ruta correcta en el formato de cadena. NO USE toString() porque agregará texto de formato adicional que TOTALMENTE LEVANTARÁ el nombre del archivo (puede probarlo y ver la impresión).

Pasamos 2 horas de depuración este ... :(

+0

¿Qué pasa con [Clase.getResourceAsStream()] (https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#getResourceAsStream-java.lang.String-)? – Lu55

1

Class.getResources sería recuperar el recurso por el cargador de clases que cargan el objeto. Mientras ClassLoader.getResource sería recuperar el recurso utilizando el cargador de clase especificada.

Cuestiones relacionadas