Language/JAVA

Class.getResource vs. ClassLoader.getResource

적외선 2014. 11. 14. 11:23

Java API Documentation에서 보면 


먼저 Class에 있는 getResource를 보자. Class는 일단 instance가 있어야 부를 수가 있다.  

public URL getResource(String name)

Finds a resource with a given name. The rules for searching resources associated with a given class are implemented by the defining class loader of the class. This method delegates to this object's class loader. If this object was loaded by the bootstrap class loader, the method delegates to ClassLoader.getSystemResource(java.lang.String).

Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:

  • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
  • Otherwise, the absolute name is of the following form:
       modified_package_name/name
     

    Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').

설명을 살펴보면 ClassLoader에 있는 getSystemResource 메소드를 사용하는데 
resource를 나타내는 String이 '/'로 시작하면 absolute path로 하고
그렇지 않으면 this object가 포함되어 있는 package의 full path라고 한다. 

다음으로 ClassLoader를 살펴 보면 
public URL getResource(String name)
Finds the resource with the given name. A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.

The name of a resource is a '/'-separated path name that identifies the resource.

This method will first search the parent class loader for the resource; if the parent is null the path of the class loader built-in to the virtual machine is searched. That failing, this method will invoke findResource(String) to find the resource.

absolute path를 사용하게 된다. 

따라서 일반적으로는 ClassLoader보다는 Class의 getResource를 사용하는 편이 낫다고들 한다. 
ClassLoader의 Security Permission 제약도 문제가 될 수 있다 하는 사람도 있다. 
getResourceAsStream도 같은 원칙으로 적용될 수 있다. 

보통 코드를 쓸 때 instance로부터 읽을 때는
this.class.getResource("def/g.xml");
this.getClass().getResource("/abc/def/g.xml") ;
라고 쓰면 된다. 

Class로부터 읽고 싶을 때도 있어서
MyClass.class.getRosource("a.xml");
이런 식으로 쓰면 될 것이다. 

출처 - http://holycall.tistory.com/entry/ClassgetResource-vs-ClassLoadergetResource





Class.getResource() 메소드는 해당 클래스의 소스 파일 위치를 상대 루트로 설정한다.

반면, ClassLoader.getResource()/getResources() 메소드는 클래스패스의 루트를 상대 루트로 설정한다.

다음은 이와 같은 차이를 보여주는 예제이다.

package test;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;

public class GetResourceExample {

 public static void main(String[] args) {
  Class<GetResourceExample> clazz = GetResourceExample.class;
  URL resource = clazz.getResource(".");
  System.out.println("resource: " + resource);

  ClassLoader classLoader = clazz.getClassLoader();
  try {
   Enumeration<URL> resources = classLoader.getResources(".");
   System.out.println("resources:");
   while (resources.hasMoreElements()) {
    URL nextElement = resources.nextElement();
    System.out.println(nextElement);
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

}

결과는 다음과 같다.

resource: file:/D:/%ec%9e%91%ec%97%85%ec%8b%a4/Java/JavaExample/bin/test/
resources:
file:/D:/%ec%9e%91%ec%97%85%ec%8b%a4/Java/JavaExample/bin/


Class.getResource() 메소드의 경우

해당 클래스가 포함된 패키지에 따른 디렉토리를 현재 디렉토리로 함을 알 수 있다.

반면, ClassLoader.getResources() 메소드의 경우

클래스패스의 루트를 현재 디렉토리로 함을 확인할 수 있다.


출처 - http://devday.tistory.com/entry/ClassgetResource-vs-ClassLoadergetResourcegetResources