ClassLoader (CurrentClassLoader, ParentClassLoader 및 ContextClassLoader) 에 대해 다시 이야기 합 니 다.

Tomcat 의 Catalina 의 Lifecycle 과 Container 인터페이스 에 영감 을 받 아 하나의 애플 리 케 이 션 서버 를 만들어 서 여러 애플 리 케 이 션 을 각자 의 classpath 에서 독립 적 으로 실행 시 키 려 고 했 으 나 Current ClassLoader, Parent ClassLoader 와 ContextClassLoader 에 의 해 곤 혹 스 러 워 했 습 니 다. 이제 야 그들의 관 계 를 알 게 되 었 습 니 다. 여러분 과 공유 하고 싶 습 니 다.
내 생각 은 전체 응용 서버 가 다음 과 같은 xml 로 설정 되 어 있다 는 것 이다.

<App name="Server">
	<App name="s1" path="...">
		<App name="s1_1" path="..." />
	</App>
	<App name="s2" path="...">
		<App name="s2_1" path="..." />
	</App>
</App>

모든 앱 은 하나의 애플 리 케 이 션 이자 용기 입 니 다. 맨 위 에 있 는 앱 은 바로 이 애플 리 케 이 션 서버 자체 입 니 다.응용 서버 자체 와 응용 은 완전히 평등 하 며, 모든 외부 용기 (응용) 는 내부 의 모든 용기 (응용) 의 생명 주 기 를 재 귀적 으로 책임 집 니 다.
path 에 대응 하 는 디 렉 터 리 아래 에 두 개의 하위 디 렉 터 리 가 있어 야 합 니 다. 각각 lib 와 classes 입 니 다. 이 두 디 렉 터 리 는 이 응용 프로그램의 classpath 를 정의 합 니 다. 응용 사이 에 다른 응용 프로그램의 classpath 가 보이 지 않 고 내부 응용 만 외층 을 볼 수 있 습 니 다.
문 제 는 이 스 레 드 에서 실행 되 는 코드 를 지정 한 ClassLoader 에서 클래스 의 정 의 를 찾 을 수 있 도록 스 레 드 를 시작 하 는 방법 입 니 다.
이 문 제 를 해결 하기 위해 서 우 리 는 코드 를 좀 보 았 다.우 리 는 다음 세 가지 방법 으로 하나의 경로 에서 URLClassLoader 를 생 성 합 니 다.

private static ClassLoader createClassLoader(String path) throws Exception {
		List<File> jarList = new ArrayList<File>();
		getClassPath(jarList, new Filter(), new File(path, "lib"));

		List<URL> urlList = new ArrayList<URL>();
		urlList.add(new URL("file:///" + path + "/classes/"));

		for (int i = 0; i < jarList.size(); ++i) {
			urlList.add(new URL("file:///"
					+ ((File) jarList.get(i)).getCanonicalPath()));
		}
		return new URLClassLoader((URL[]) urlList.toArray(new URL[0]), Thread
				.currentThread().getContextClassLoader());
	}

	private static void getClassPath(List<File> list, Filter filter, File f) {
		if (f.exists() && f.isDirectory()) {
			File[] ss = f.listFiles(filter);
			for (int i = 0; i < ss.length; ++i) {
				if (ss[i].isFile()) {
					list.add(ss[i]);
				} else if (ss[i].isDirectory()) {
					getClassPath(list, filter, ss[i]);
				}
			}
		}
	}

	private static class Filter implements FilenameFilter {
		public boolean accept(File dir, String name) {
			File f = new File(dir, name);
			boolean isDir = f.isDirectory();
			boolean isFile = f.isFile();
			boolean isJar = name.toLowerCase().endsWith(".jar");
			boolean isZip = name.toLowerCase().endsWith(".zip");
			return (isFile && (isJar || isZip)) || isDir;
		}
	}

createClassLoader 방법 은 path 디 렉 터 리 에 있 는 lib 와 classes 두 디 렉 터 리 에서 클래스 의 정 의 를 찾 고 해당 하 는 URLClassLoader 를 되 돌려 줍 니 다.이것 이 첫걸음 이다.
다음은 이 스 레 드 에서 실행 중인 코드 를 createClassLoader 가 돌아 오 는 ClassLoader 의 classpath 에서 클래스 정 의 를 찾 고 새 스 레 드 (App) 의 ParentClassLoader 를 시작 하 는 스 레 드 로 설정 하고 새 스 레 드 (App) 를 설정 해 야 합 니 다.의 ContextClassLoader 를 createClassLoader 로 되 돌려 주 는 ClassLoader 입 니 다.우 리 는 먼저 새 스 레 드 (App) 의 코드 를 봅 니 다.

package test;
public class T extends Thread {
	public void run() {
		System.out.println("App context: "
				+ Thread.currentThread().getContextClassLoader());
		System.out.println("App parent: "
				+ this.getClass().getClassLoader().getParent());
		System.out.println("App current: " + this.getClass().getClassLoader());

	}
}

마지막 으로 코드 로 이 테스트 프로그램 을 시작 합 니 다:

public static void main(String[] args) throws Exception {
		ClassLoader appClassLoader = createClassLoader("D:/P/eclipse/workspace/TestApp");
		Class c = appClassLoader.loadClass("test.T");
		Object t = c.newInstance();

		Method setContextClassLoader = c.getMethod("setContextClassLoader",
				new Class[] { ClassLoader.class });
		setContextClassLoader.invoke(t, appClassLoader);

		Method start = c.getMethod("start", new Class[] {});
		start.invoke(t, new Object[] {});
		System.out.println("Main context: "
				+ Thread.currentThread().getContextClassLoader());
		System.out.println("Main current: " + Test.class.getClassLoader());
		System.out.println("Main parent: "
				+ Test.class.getClassLoader().getParent());

		System.out.println("App ClassLoader: " + appClassLoader);
		System.out.println("Systen ClassLoader: "
				+ ClassLoader.getSystemClassLoader());
	}

출력 결 과 는:

Main context: sun.misc.Launcher$AppClassLoader@11b86e7
Main current: sun.misc.Launcher$AppClassLoader@11b86e7
Main parent: sun.misc.Launcher$ExtClassLoader@35ce36
App ClassLoader: java.net.URLClassLoader@addbf1
Systen ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
App context: java.net.URLClassLoader@addbf1
App parent: sun.misc.Launcher$AppClassLoader@11b86e7
App current: java.net.URLClassLoader@addbf1

메 인 은 바깥쪽 용 기 를, 앱 은 안쪽 용 기 를 대표 한다.이때 앱 의 ContextClassLoader 와 CurrentClassLoader 는 모두 우리 가 createClasLoader 방법 으로 만 든 ClassLoader 이 고, ParentClassLoader 는 외층 용기 의 CurrentClassLoader 이 며, SystemClassLoader 가 이 예 에 있 는 것 을 발견 했다.
이제 우리 스스로 애플 리 케 이 션 서버 를 만 드 는 것 을 막 을 만 한 것 은 아무것도 없다.

좋은 웹페이지 즐겨찾기