헤르메스 LIFE

[문서] Understanding Class.forName 본문

문서

[문서] Understanding Class.forName

헤르메스의날개 2012. 5. 16. 10:02
728x90

Understanding Class.forName


http://media.techtarget.com/tss/static/articles/content/dm_classForname/DynLoad.pdf


참고

http://whiteship.tistory.com/2593


1. 클래스를 로딩할 때 사용하는 클래스로더 차이

인자가 한개 짜리인 forName(String) 메서드는 클래스를 로딩할 때 사용하는 클래스로더가 저 코드를 실행하는 클래스로더가 됩니다. 하지만 ClassLoader.loadClass()를 사용하면 당연히 자기 자신을 사용해서 클래스 로딩을 실행하게 되죠. (그렇다고 해서 반드시 해당 클래스로더가 읽어온다는 보장은 없죠. 그 부모가 읽어올 수도 있고 클래스 패스에 없을 수도 있고 암튼 여기서 로딩한다는 건 로딩을 시도한다고 보시기 바랍니다.)

하지만 Class.forName(String, boolean, ClassLoader)를 사용하면 클래스 로더를 지정해 줄 수 있습니다.

2. 초기화

Class.forName(String) 메서드를 사용하면 곧바로 클래스의 static 초기화 블럭과 static 멤버 변수의 값을 초기화 합니다. 하지만 ClassLoader.loadClass()를 사용하면 해당 클래스를 처음으로 사용하기 전까지 초기화가 지연됩니다.

이것 역시 Class.forName(String, boolean, ClassLoader)의 두번째 인자값을 이용하여 조절할 수 있습니다.

- 클래스 초기화 에러

만약 Class.forName(String)을 사용해서 로딩할 때 static 영역에서 에러가 난다면 해당 클래스는 다시 로딩할 수가 없습니다. 특정 클래스로더가 일단 로딩한 클래스는 다시 로딩할 수가 없죠. 그래서 NoClassDefinitionFound 에러가 날 수도 있습니다.

이때는 해당 클래스로더 인스턴스를 버리고 새로 만들어야 하는데 그럴 때를 대비해 인자 세개짜리 forName을 쓰라는군요. 

결국 forName()으로 클래스를 로딩할 떄는 별 개의 클래스로더를 쓰라는건데... 흠.. 그렇게 단순해 보이지가 않는데;; 머 클래스로더를 지정해 둔다고 해봤자. 보통 App CL로 읽어올테고 그럼 App CL 인스턴스를 버리라고?? 에이;; 그건 좀.. 

forName으로 읽어올 클래스를 클래스패스를 가지고 있으면서 parent로 위임하지도 않는 CL을 이용해서 forName으로 읽은 경우라면 뭐 괜찮을지도.. 어쨋거나 직접 통제가 가능한 클래스로더를 사용해야 겠군요.


참고

http://whiteship.tistory.com/2596 

pdf: http://www.theserverside.com/tt/articles/content/dm_classForname/DynLoad.pdf

먼저 간단한 퀴즈로 시작하는.. 긴 문서..


이 코드가 문제를 일으킬 수 있는 상황은 저 클래스를 자바 Extentions 폴더 (<JDK>/jre/lib/ext 또는 <JRE>/lib/ext)에 놓았을 경우입니다. 그렇지 않고 그냥 CLASSPATH에 둘었다면 별 문제가 없을 가능성이 큽니다. 대체 저런식으로 동적으로 로딩하려는 클래스들이 App CL의 CLASSLOADER에 있기 마련일 테니까요.

하지만, Extention 폴더로 이동하면 무슨일이 벌어질까요. ClassNotFoundExcepion이 발생합니다. 그 원인을 정확히 모르신다면 ClassLoader에 대한 아주 기본적인 개념이 부족한거라 봐도 무방하겠습니다.

이 글에서 그에 대한 해결책 두 개를 제공해주며, 그 중 하나가 바로 쓰레드 컨텍스트 클래스로더를 사용하는 것입니다. 

http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#getContextClassLoader%28%29

Returns the context ClassLoader for this Thread. The context ClassLoader is provided by the creator of the thread for use by code running in this thread when loading classes and resources. If not set, the default is the ClassLoader context of the parent Thread. The context ClassLoader of the primordial thread is typically set to the class loader used to load the application.

First, if there is a security manager, and the caller's class loader is not null and the caller's class loader is not the same as or an ancestor of the context class loader for the thread whose context class loader is being requested, then the security manager's checkPermission method is called with a RuntimePermission("getClassLoader") permission to see if it's ok to get the context ClassLoader.

별짓을 하지 않는다면 쓰레드 컨텍스트 클래스로더는 System(또는 Application) CL이 됩니다. 따라서 저 위의 코드를 자바 extentions 폴더에 넣고 실행하더라도 쓰레드 컨텍스트 클래스로더를 가져와서 loadClass를 호출하면 아무런 문제없이 동작합니다.

안그래도 대체 Thread Context ClassLoader가 왜 생긴건지 궁금했는데 이 글을 통해서 짐작할 수 있게 됐습니다. 클래스로더 계층 구조를 만들 때, 예를 들어 톰캣의 Common CL 같은 녀석은 자기 하위의 CL인 WebAPP CL에 어떤 클래스들이 들어올지 모를겁니다. 하지만 그런 상태에서 Common CL에서 WebAPP CL에서만 로딩할 수 있는 어떤 클래스를 로딩할 필요가 있다면... WebAPP CL을 직접 참조하지 않고 바로 Thread Context ClassLoader를 사용해서 로딩하도록 코딩을 하면 로딩할 수 있게 되는거죠.

흠.. 하지만 이.. 미적지근한 느낌은 뭘까요.. 왠지 상위 CL에서 하위 CL의 클래스패스에 있는걸 로딩해버리면 왠지 꼬여버릴 것만 같은 이 기분... 아.. 불안해. 왜 그럴까나..  

728x90