자바 는 클래스 경로 에서 자원 을 정확하게 가 져 옵 니 다.

자바 는 다음 과 같은 몇 가지 방법 으로 자원 에 접근 할 수 있 습 니 다.
  • Class 의 getResource 방법
  • ClassLoader 의 getResource 방법
  • ClassLoader 의 getSystem Resource 정적 방법
  • 사용 중,Class 는 클래스 의 class 속성 을 직접 인용 하여 얻 거나,실례 적 인 getClass()방법 으로 얻 을 수 있 습 니 다.ClassLoader 를 가 져 오 는 방법 이 많 습 니 다.다음 과 같은 몇 가지 가 있 습 니 다.
  • 클래스 의 getClassLoader 방법 을 호출 합 니 다.예 를 들 어 getClass().getClassLoader()
  • 현재 스 레 드 에서 ClassLoader:Thread.currentThread().getContextClassLoader()
  • 가 져 오기
  • 시스템 ClassLoader 가 져 오기:ClassLoader.getSystem ClassLoader()
  • 그러나 자바 의 ClassLoader 개념 에 대해 잘 모른다 면 사용 을 피 하 는 것 이 좋다.
    Class.getResource 와 ClassLoader.getResource 의 차이
    이 두 가지 방식 은 모두 하나의 문자열 형식의 경로 표현 식,즉 자원 이름 을 받 아들 이 고 찾 은 자원 의 URL 을 되 돌려 줍 니 다.두 가지 방식 은 모두 자원 을 포 지 셔 닝 하 는 데 사용 할 수 있 는데 인터넷 에서 전해 지 는 글 에서 둘 다 흔히 볼 수 있다.실제로 Class 의 getResource 방법 도 ClassLoader 의 getResource 방법 을 호출 했 지만 둘 은 매우 큰 차이 가 있 기 때문에 이 두 가지 방법의 차 이 를 모 르 면 위험 을 초래 하기 쉽다.위험 은 항상 작성 할 때 오류 가 발생 하 는 것 보다 훨씬 무 섭 습 니 다.왜냐하면 특정한 상황 에서 정상 적 이 고 쉽게 발견 되 지 않 기 때 문 입 니 다.
    둘 의 가장 큰 차 이 는 어디서부터 자원 을 찾 느 냐 하 는 것 이다.ClassLoader 는 현재 클래스 의 패키지 이름 경로 에 관심 이 없습니다.classpath 를 기반 으로 자원 을 찾 습 니 다.한편,Class.getResource 는 자원 이름 이 절대 경로("/"로 시작)라면 시작 하 는"/"를 제거 하고 ClassLoader 의 getResource 방법 으로 자원 을 찾 습 니 다.자원 이름 이 상대 경로 라면 현재 패키지 경로 아래 에서 자원 을 찾 습 니 다.
    예 를 들 어 우리 에 게 test.app(가방 이름 은 test)이 있 고 test 가방 아래 에 같은 이름 의 js 파일 이 있 으 며 App.js 라 고 가정 합 니 다.이 js 파일 을 ClassLoader 로 가 져 오 려 면 이렇게 써 야 합 니 다:
    
    App.class.getClassLoader().getResource("test/App.js");
    Class 의 getResource 방법 을 사용 하면 두 가지 방법 이 있 습 니 다.
  • 사용 상대 경로:
  • 
    App.class.getResource("App.js");
  • 사용 절대 경로:
  • 
    App.class.getResource("/test/App.js");
    위의 예 를 보면 둘 사이 의 커 다란 차 이 를 알 수 있다.어떤 사람들 은 인터넷 에서 비슷 한 코드 를 복사 하여 정확하게 실행 되 지 않 는 것 을 보고 자원 이름 앞 에'/'를 붙 이거 나 시작 하 는'/'를 없 애 려 고 시도 하기 시작 했다.시험 에 성공 하면 완 공 된 셈 이다.이것 은 결코 정도 가 아니다.
    Class 와 ClassLoader 의 getResource 방법 은 또 다른 차이 가 있 습 니 다.Class 의 getResource 방법 에 있어 서 상대 적 인 경로 가 들 어 오 면 패키지 이름과 경로 이름 의 전환 을 시도 합 니 다.Class.getResource 방법의 원본 코드 를 보면 자원 이름 에 resolveName 방법 을 먼저 호출 한 다음 에 ClassLoader 의 getResource 방법 을 호출 하여 자원 의 포 지 셔 닝 을 완성 하 는 것 을 볼 수 있 습 니 다.
    테스트 코드
    프 리 젠 테 이 션 으로 Class 와 ClassLoader 의 getResource 방법 을 보 여 주 는 다음 코드 를 썼 습 니 다.
    
    /**
     * Copyright (c) 2014 Chen Zhiqiang <[email protected]>. Released under the MIT license.
     */
    package test;
    
    import java.net.URL;
    import java.util.Enumeration;
    
    /**
     * Tests for the use of {@link Class#getResource(String)} and
     * {@link ClassLoader#getResource(String)}.
     * 
     * @author Chen Zhiqiang <[email protected]>
     */
    public class ClassResourceTest {
        Class<ClassResourceTest> cls = ClassResourceTest.class;
        ClassLoader ldr = cls.getClassLoader(); // Thread.currentThread().getContextClassLoader()
    
        public static void println(Object s) {
            System.out.println(s);
        }
    
        void showResource(String name) {
            println("## Test resource for: “" + name + "” ##");
            println(String.format("ClassLoader#getResource(\"%s\")=%s", name, ldr.getResource(name)));
            println(String.format("Class#getResource(\"%s\")=%s", name, cls.getResource(name)));
        }
        public final void testForResource() throws Exception {
            showResource("");
            showResource("/");
            showResource(cls.getSimpleName() + ".class");
            String n = cls.getName().replace('.', '/') + ".class";
            showResource(n);
            showResource("/" + n);
            showResource("java/lang/Object.class");
            showResource("/java/lang/Object.class");
        }
    
        public static void main(String[] args) throws Exception {
            println("java.class.path: " + System.getProperty("java.class.path"));
            println("user.dir: " + System.getProperty("user.dir"));
            println("");
            ClassResourceTest t = new ClassResourceTest();
            t.testForResource();
        }
    }
    위 코드 를 컴 파일 하여 서로 다른 자원 경로 의 출력 결 과 를 보십시오.
    Jar 가방 으로 포장 한 후의 변화
    현재 상기 코드 를 컴 파일 한 결 과 를 Jar 파일 로 포장 하고 test.jar 라 고 가정 한 다음 에 이 jar 패키지 에서 상기 코드 를 실행 한 다음 에 출력 결 과 를 보고 위의 출력 과 어떤 변화 가 있 는 지 비교 해 보 세 요.
    
    java -classpath test.jar test.ClassResourceTest
    주의해 야 할 몇 가지:
  • Class.getResource(")에 다른 출력 이 있 습 니 다.결 과 는 jar:file:/some 입 니 다.path/test.jar!/some_path,Jar 로 포장 하기 전에 출력 형식 은 file:/some 입 니 다.path...;
  • Class.getResource("/")는 null 이 고 포장 하기 전에 이 출력 은 ClassResourceTest 의 클래스 경로 입 니 다.
  • ClassLoader.getResource(")는 null 이 고 포장 하기 전에 이 출력 은 ClassResourceTest 의 클래스 경로 입 니 다.
  • 에서 ClassLoader.getResource 방법 을 호출 할 때 자원 이름 이 절대 경로 라면 포장 여부 와 상 관 없 이 출력 결 과 는 null 입 니 다.적어도 저 에 게 는 이 렇 습 니 다.
  • 오류 와 함정
  • 은 클래스 경로 의 루트 로 Class.getResource("/")나 ClassLoader.getResource(")를 사용 합 니 다.
  • 이것 은 흔히 볼 수 있 는 오류 로 인터넷 에 널리 퍼 져 있다.그것들 은 Jar 가방 으로 포장 한 후에 그 결과 에 변화 가 생 길 것 이다.
  • getResource 방법의 출력 을 얻 은 후 결 과 를 getFile 이나 getPath 로 간단하게 호출 하고 파일 경로 로 처리 합 니 다.
  • 자원 은 파일 과 디 렉 터 리 형식 으로 클래스 경로 에 있 을 수 있 지만 Jar 패키지 나 Zip 패키지 에 포 장 될 수도 있 습 니 다.코드 가 포장 되 지 않 는 다 고 가정 할 수 없습니다.
  • 은 절대 경 로 를 ClassLoader 에 전달 하 는 getResource 방법 입 니 다.
  • 인터넷 에 서 는 ClassLoader 의 getResource 방법 에 있어 서 자원 이름 이'/'로 시작 하 는 지 여 부 는 같 지만,저 에 게 는 ClassLoader 의 getResource 방법 이 절대 경 로 를 받 아들 이지 않 고 출력 결 과 는 null 입 니 다.
    getResource 방법 을 정확하게 사용 합 니 다.
  • 은 Class.getResource("/")나 ClassLoader.getResource(")를 사용 하지 마 십시오.너 는 정확 한 자원 이름 을 입력 한 후에 출력 결 과 를 계산 해 야 한다.예 를 들 어 현재 클래스 가 어떤 경로 에서 시작 되 었 는 지 확인 하고 싶다 면 앞에서 언급 한 test.App 에 서 는 App.class.getResource(App.class.getSimple Name()+"class"를 호출 할 수 있 습 니 다.만약 에 얻 은 결과 가 jar 프로 토 콜 의 URL 이 아니라면 class 파일 이 포장 되 지 않 았 음 을 설명 하고 얻 은 결 과 를 끝의"test/app.class"를 제거 하면 test.app 의 클래스 경로 의 출발점 을 얻 을 수 있 습 니 다.결과 가 jar 프로 토 콜 의 URL 이 라면 끝 부분 을 제거 합 니 다."!/test/app.class"와 앞의"jar:",즉 test.app 이 있 는 jar 파일 의 url 입 니 다.
  • 같은 가방 의 자원 을 찾 으 려 면 그 종류의 getResource 방법 을 사용 하고 상대 적 인 경 로 를 사용 하 십시오.앞에서 말 한 바 와 같이 test.app.class 와 같은 가방 에 있 는 App.js 파일 을 가 져 오 려 면 사용 해 야 합 니 다. App.class.getResource("App.js") 。물론 절대적 인 것 은 없습니다.ClassLoader.getResource("test/app.js")를 사용 하 셔 도 됩 니 다.이것 은 당신 이 직면 한 문제 가 무엇 인지 에 달 려 있 습 니 다.
  • ClassLoader 에 대해 잘 모 르 면 Class 의 getResource 방법 을 사용 하 십시오.
  • 이 Class.getResource 방법 에 전달 할 상대 적 인 경 로 를 이해 하지 못 하거나 확인 하지 못 하면 클래스 경로 의 맨 위 패키지 경 로 를 참고 로'/'로 시작 하 는 경 로 를 항상 전달 합 니 다.
  • 디 버 깅 환경 이 마지막 운행 환경 이 라 고 가정 하지 마 세 요.당신 의 코드 는 포장 하지 않 을 수도 있 고 포장 할 수도 있 습 니 다.당신 은 이런 상황 을 고려 해 야 합 니 다.구 덩이 를 묻 지 마 세 요.
  • getResource:매 거 진 자원
    자바 의 CLASSPATH 는 하나의 경로 목록 이기 때문에 여러 종류의 경로 에서 같은 자원 이름 이 나타 날 수 있 습 니 다.그것들 을 열거 하려 면 ClassLoader 의 getResources 방법 을 사용 할 수 있 습 니 다.
    다음 코드 는 모든"META-INF/MANIFEST.MF"를 열거 할 수 있 으 며,클래스 경로 에 어떤 jar 파일 이 이 자원 을 포함 하고 있 는 지 관찰 할 수 있 습 니 다.
    
    import java.net.URL;
    import java.util.Enumeration;
    public class Test {
        public static void main(String[] args) throws Exception {
            ClassLoader ldr = Test.class.getClassLoader();
            System.out.println("## Test for getResources(‘META-INF/MANIFEST.MF') ##");
            Enumeration<URL> urls = ldr.getResources("META-INF/MANIFEST.MF");
            while(urls.hasMoreElements())
                System.out.println(urls.nextElement());
        }
    }
    실례
    다음 코드 는 코드 의 클래스 경로 시작 점 을 정확하게 가 져 오 는 방법 을 보 여 줍 니 다.
    
    /**
     * Copyright (c) 2014 Chen Zhiqiang <[email protected]>. Released under the MIT license.
     */
    package test;
    
    import java.io.File;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     *               
     * 
     * @author Chen Zhiqiang <[email protected]>
     */
    public class AppDirTest {
    	Classcls = AppDirTest.class;
    	URL codeLocation = getCodeLocation();
    
    	/**
    	 * Get the code location.
    	 * 
    	 * Return the classpath where the code run from. The return url will be:
    	 *   file:/path/my-app/calsses/ or file:/path/my-app/my-app.jar
    	 *
    	 * @return URL
    	 */
    	public URL getCodeLocation() {
    		if (codeLocation != null)
    			return codeLocation;
    		// Get code location using the CodeSource
    		codeLocation = cls.getProtectionDomain().getCodeSource().getLocation();
    		if (codeLocation != null)
    			return codeLocation;
    		// If CodeSource didn't work, use {@link } Class.getResource instead.
    		URL r = cls.getResource("");
    		synchronized (r) {
    			String s = r.toString();
    			Pattern jar_re = Pattern.compile("jar:\\s?(.*)!/.*");
    			Matcher m = jar_re.matcher(s);
    			if (m.find()) { // the code is run from a jar file.
    				s = m.group(1);
    			} else {
    				String p = cls.getPackage().getName().replace('.', '/');
    				s = s.substring(0, s.lastIndexOf(p));
    			}
    			try {
    				codeLocation = new URL(s);
    			} catch (MalformedURLException e) {
    				throw new RuntimeException(e);
    			}
    		}
    		return codeLocation;
    	}
    
    	/**
    	 * Get the class path root where the program startup, if run in a jar,
    	 * return the jar file's parent path.
    	 * 
    	 * @return
    	 */
    	public String getAppDir() {
    		File f = new File(getCodeLocation().getPath());
    		return f.isFile() ? f.getParent() : f.getPath();
    	}
    
    	public static void main(String[] args) {
    		AppDirTest t = new AppDirTest();
    		System.out.println("code location: " + t.getCodeLocation());
    		System.out.println("app dir: " + t.getAppDir());
    	}
    
    }
    이상 은 자바 가 클래스 경로 에서 자원 을 정확하게 얻 는 상세 한 내용 입 니 다.자바 가 클래스 경로 에서 자원 을 얻 는 것 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

    좋은 웹페이지 즐겨찾기