Class.getResource ()와 ClassLoader.getResource ()의 차이점은 무엇입니까?


194

나는 차이가 사이 궁금해 Class.getResource()하고 ClassLoader.getResource()?

편집 : 특히 캐싱이 파일 / 디렉토리 레벨에 관련되어 있는지 알고 싶습니다. "클래스 버전으로 디렉토리 목록이 캐시됩니까?"에서와 같이

AFAIK 다음은 본질적으로 동일해야하지만 그렇지는 않습니다.

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

WEB-INF/classes/해당 디렉토리의 기존 파일에서 새 파일을 작성하는 일부 보고서 생성 코드를 사용하여이를 발견했습니다 . Class의 메서드를 사용할 때을 사용하여 배포 getClass().getResource()할 때 있던 파일을 찾을 수 있지만 새로 만든 파일을 가져 오려고 할 때 null 객체 를 받았습니다 . 디렉토리를 찾아 보면 새 파일이 있다는 것을 명확하게 보여줍니다. 파일 이름 앞에는 "/myFile.txt"와 같이 슬래시가 붙습니다.

반면 ClassLoader버전은 getResource()생성 된 파일을 찾았습니다. 이 경험을 통해 어떤 종류의 디렉토리 목록을 캐싱하는 것 같습니다. 맞습니까? 그렇다면 어디에 기록되어 있습니까?

로부터 API 문서Class.getResource()

지정된 이름의 리소스를 찾습니다. 주어진 클래스와 연관된 자원을 검색하기위한 규칙은 클래스의 정의 클래스 로더에 의해 구현됩니다. 이 메소드는이 객체의 클래스 로더에 위임합니다. 부트 스트랩 클래스 로더가이 객체를로드 한 경우, 메소드는 ClassLoader.getSystemResource (java.lang.String)에 위임됩니다.

나에게 이것은 "Class.getResource가 실제로 자신의 classloader의 getResource ()를 호출하고있다"고 읽습니다. 어느 것과 같은 것 getClass().getClassLoader().getResource()입니다. 그러나 분명히 그렇지 않습니다. 누군가이 문제에 대해 조명을 제공해 주시겠습니까?

답변:


6

캐싱이 진행 중인지 여부에 대한 질문에 대답합니다.

getResourceAsStream ClassLoader 메소드를 사용하여 디스크에서 파일을 지속적으로로드하는 독립형 Java 애플리케이션을 실행하여이 점을 추가로 조사했습니다. 파일을 편집 할 수 있었고 변경 사항이 즉시 반영되었습니다. 즉, 파일이 캐싱없이 디스크에서 다시로드되었습니다.

하나: 나는 서로 의존하는 여러 maven 모듈과 웹 프로젝트로 프로젝트를 진행하고 있습니다. 웹 프로젝트를 컴파일하고 실행하기 위해 IntelliJ를 IDE로 사용하고 있습니다.

위의 내용이 더 이상 사실이 아닌 것처럼 보였습니다.로드 된 파일이 이제 항아리에 구워지고 종속 웹 프로젝트에 배포되기 때문입니다. 대상 폴더의 파일을 변경하려고 시도한 후에 만 ​​사용할 수 있습니다. 이것은 캐싱이 진행되는 것처럼 보입니다.


나도 Maven과 IntelliJ를 사용했기 때문에 이것이 내 것과 가장 일치하고 질문 # 2에 대한 합리적인 설명이있는 환경입니다.
oligofren

251

Class.getResource"상대적"리소스 이름을 사용할 수 있으며, 이는 클래스 패키지와 관련하여 처리됩니다. 또는 선행 슬래시를 사용하여 "절대"리소스 이름을 지정할 수 있습니다. 클래스 로더 리소스 경로는 항상 절대적인 것으로 간주됩니다.

따라서 다음은 기본적으로 동일합니다.

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

그리고 이것도 마찬가지입니다 (그러나 그것들은 위와 다릅니다) :

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

명확한 예를 가진 좋은 대답. 게시물이 실제로 두 가지 질문에 대한 답을 얻도록 의도되었지만 두 번째 질문이 숨겨져 있음을 알았습니다. 이것을 반영하기 위해 게시물을 어떻게 업데이트해야하는지 잘 모르겠지만, 두 번째로 알고 싶은 것은 이것입니다 (다음 주석) :
oligofren

2
Class.getResource () 버전에서 어떤 종류의 캐싱이 진행되고 있습니까? 이것이 Jasper 보고서의 생성이라고 믿게 된 이유는 다음과 같습니다. getClass (). getResource ( "/ aDocument.jrxml")를 사용하여 jasper xml 파일을 가져옵니다. 그런 다음 이진 재스퍼 파일이 동일한 디렉토리에 생성됩니다 . getClass (). getResource ( "/ aDocument.jasper")는 동일한 레벨 (입력 파일)에서 문서를 명확하게 찾을 수 있지만 찾을 수는 없습니다. ClassLoader.getResource ()가 디렉토리 목록의 캐싱을 사용하지 않는 것 같으므로 도움이되는 곳입니다. 그러나 이것에 관한 문서를 찾을 수 없습니다.
oligofren

2
@oligofren : 흠 ... Class.getResource ()가 거기에서 어떤 캐싱을하기를 기대 하지 않을 것입니다 .
Jon Skeet

1
@JonSkeet 왜 this.getClass().getClassLoader().getResource("/");null을 반환합니까? this.getClass().getClassLoader().getResource(".");
Asif Mushtaq

@UnKnown : 아마도 그것에 대해 새로운 질문을해야한다고 생각합니다.
Jon Skeet

22

첫 번째 호출은 .class파일을 기준으로 검색하고 후자는 클래스 경로 루트를 기준으로 검색합니다.

그런 문제를 디버깅하기 위해 URL을 인쇄합니다.

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

3
나는 "classloader root"가 "classpath root"보다 더 정확할 것이라고 생각합니다.
Jon Skeet

4
파일 이름 앞에 "/"가
붙으면

2
재미있는 ... getClass (). getResource ( "/ someAbsPath")가 /path/to/mylib.jar!/someAbsPath 및 getClass (). getClassLoafer (). getResource ( "형식의 URL을 반환하는 경우가 있습니다. / someAbsPath ") null 반환 ..."classloader의 루트 "는 잘 정의 된 개념이 아닌 것 같습니다 ...
Pierre Henry


8
@PierreHenry : getClassLoader().getResource("/...")항상 반환 null-클래스 로더는 /경로 에서 행간 을 제거하지 않으므로 조회가 항상 실패합니다. 클래스 경로에 상대적인 절대 경로로 getClass().getResource()시작 만 처리합니다 /.
Aaron Digulla

17

사양에서 찾아야했습니다.

클래스의 getResource ()-문서에 다음과 같은 차이점이 있습니다.

이 메소드는 자원 이름을 변경 한 후 클래스 로더에 대한 호출을 위임합니다. 자원 이름이 "/"로 시작하면 변경되지 않습니다. 그렇지 않으면 "."을 변환 한 후 패키지 이름 앞에 리소스 이름이 붙습니다. "/". 부트 스트랩 로더가이 객체를로드 한 경우 호출이 ClassLoader.getSystemResource에 위임됩니다.


2
디렉토리 목록을 캐시하는지 여부에 대한 정보가 있습니까? 이것은 입력 파일을 처음 찾은 다음 동일한 디렉토리에서이를 사용하여 파일을 작성할 때 두 방법의 주요 차이점이었습니다. 클래스 버전에서 클래스 로더를 찾지 못했습니다 ( "/file.txt"를 사용하여).
oligofren

11

이 질문에 대한 답변뿐만 아니라 여기에있는 모든 답변은 "/foo/bar.properties"와 같은 절대 URL을로드하는 것이 class.getResourceAsStream(String)and로 동일하게 처리되었음을 제안합니다 class.getClassLoader().getResourceAsStream(String). 적어도 Tomcat 구성 / 버전 (현재 7.0.40)에는 해당되지 않습니다.

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

죄송합니다, 나는 만족스러운 설명이 없지만 tomcat은 클래스 로더와 함께 더러운 트릭과 그의 검은 마술을하고 차이를 유발한다고 생각합니다. 나는 항상 class.getResourceAsStream(String)과거에 사용 했지만 아무런 문제가 없었습니다.

추신 : 나는 또한 이것을 여기에 게시했습니다 .


이 문제는 내가 내에서 그것에 대해 단락을 추가 버전 8에 고정 톰캣에서 버그가 수 있도록 나타납니다 이 질문에 대한 대답
LordOfThePigs

2

Class.getResources객체를로드하는 클래스 로더에 의해 리소스를 검색합니다. 동안은 ClassLoader.getResource지정된 클래스 로더를 사용하여 리소스를 검색 할 것입니다.


0

패키지 중 하나에있는 input1.txt 에서 읽으려는 클래스와 함께 읽으려고했습니다.

다음과 같이 작동합니다.

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

System.out.println(fileName);

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

가장 중요한 부분은 getPath()문자열 형식의 올바른 경로 이름을 원하면 호출 하는 것입니다. fileName을 완전히 제거하는 추가 서식 텍스트를 추가하므로 사용하지 마십시오toString() (시도하고 인쇄 할 수 있음).

이것을 디버깅하는 데 2 ​​시간이 걸렸습니다 ... :(



리소스는 파일이 아닙니다. JAR 또는 WAR 파일에서 압축을 풀지 못 FileReader하거나 FileInputStream액세스 할 수 없거나 사용할 수없는 경우입니다. 대답이 맞지 않습니다.
Lorne의 후작
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.