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

나는 차이가 사이 궁금해 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()입니다. 그러나 분명히 그렇지 않습니다. 누군가이 문제에 대해 조명을 제공해 주시겠습니까?



답변

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

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

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

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


답변

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");


답변

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

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

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


답변

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

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

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


답변

이 질문에 대한 답변뿐만 아니라 여기에있는 모든 답변은 “/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)과거에 사용 했지만 아무런 문제가 없었습니다.

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


답변

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


답변

패키지 중 하나에있는 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 ​​시간이 걸렸습니다 … 🙁