원문은 다음 링크에서 보실 수 있습니다.

http://jboss.org/community/docs/DOC-13267

JBoss ClassLoader History

이 문서는 JBoss ClassLoader의 진화 과정과, 앞으로 어떤 부분에서 개선이 필요한지를 기술합니다. 또, 사용자 클래스 로더를 별개로 만드는 것이 매우 어렵기는 하지만, 그것과 관련한 몇 가지 재미있는 주제들에 대해 기술합니다.

JBoss-2.x - 최초로 핫 디플로이먼트를 지원한 초기 버전

JBoss 는 모든 사용자 레벨 컴포넌트들에 대해 핫 디플로이먼트 기능을 제공하는 최초의 어플리케이션 서버였습니다.이전의 서블릿 컨테이너들은 사용자가 서블릿 클래스들만을 변경할 수 있도록 해 주었지만, JBoss는 이 기능을 EJB 컨테이너 및 리소스 어댑터까지 확장하였습니다.

시스템 레벨 클래스들에 대해서는 ClassPathExtension MBean이 제공되었습니다. 실제로는 이것은 java.class.path 시스템 변수를 수정한 것이기 때문에, 실제 사용시 사용자는 단지 JVM의 CLASSPATH 만을 변경할 수 있었고, MBean의 설정이 보다 쉽고 견고하게 이루어졌습니다.

핫 디플로이먼트는 변경 가능한 클래스들을 별개의 클래스로더 내에 고립시키는 방식으로 구현되었습니다. 이 클래스로더들은 클래스가 변경될 때 마다 버려지고 새로 생성되었습니다. CLASSPATH 내의 클래스들은 핫 디플로이가 불가능했는데, 이것은 시스템 클래스로더를 재 생성할 수 있는 방법이 없었기 때문입니다. (시스템 클래스로더는 JRE의 제어를 받습니다.)

좀더 시간이 흐른 후, 어떤 것들이 변경 가한지에 대한 몇가지 명확한 제약 사항을 추가로 제공하는 방식을 사용하여, 클래스를 재정의하기 위해 에이전트를 사용할 수 있게 되었습니다.

자 바 클래스로더는 본질적으로 계층적(hierarchical) 구조를 갖기 때문에, 몇몇 클래스를만을 위해 분리된 클래스로더를 갖는 방식은 클래스 공유를 매우 어렵게 만들었습니다. 예를 들어, 만약 사용자가 동일 EAR내에 들어있지 않은 두 개의 EJB jar 파일을 갖고 있다고 가정할때, 두 EJB jar 파일을 로딩하기 위해 사용된 각각의 클래스로더들은 서로 상대방의 클래스들을 볼 수 없게 됩니다. 이것은 잘 알려진 ClassCastException 문제를 발생시키게 되며, 이 문제는 각각의 클래스로더들이 동일 클래스에 대해 자신만의 별개의 복사본을 갖게 되었을 때 생겨납니다.
(자바 규칙상 클래스로더가 다르면, 동일한 이름을 가지고 있더라도 별개의 클래스로 취급됩니다)
만약, 성능 향상을 위하여 call by reference 기능을 사용하여 상대 클래스의 메소드를 호출하려고 한다면, 문제가 발생하게 됩니다.

당 시의 EJB 스펙은 오직 리모트 인터페이스를 통한 call by value 세만틱스만을 제공하고 있었기때문에, 이것은 원칙적으로 볼때 발생해서는 안되는 문제점이었습니다. 하지만 JBoss는 성능 향상을 위해 call by reference를 제공하는 새로운 기능을 추가하였으며, 이것은 나중에 Local Interface 라는 이름으로 EJB 스펙에 포함됩니다.

클래스로더들 간에 상대방의 클래스를 볼 수 있는 경우 조차도, 만약 클래스들이 서로 다른 클래스로더로부터 로딩된 경우라면 package private 접근 권한이 동작하지 않았습니다.

흥미롭게도, 서블릿의 동적 로딩 기능은 이제 스펙에서 제외되었습니다. 이제는 컨테이너가 해당 기능을 제공한다고 해도, 사용자가 그것을 사용하기 위해 추가적인 작업을 해주어야 합니다.

JBoss-3.x/4.x - UnifiedClassLoader와 개별(peer) 클래스로더 모델


JBoss version 3는 이전 버전에서 발견된 문제점들을 일부나마 해결하기 위한 목적으로 디자인되었으며, 더 나아가 , 서버 구현 컴포넌트들 까지도 핫 디플로이먼트가 가능하도록 하겠다는 목표로 .sar 아카이브가 도입되었습니다.

JBoss3/4 클래스로더의 세부사항은 이 위키의 여러곳에서 따로 설명되어 있기 때문에, 여기서는 주요 차이점과 이슈들에 대해서만 살펴보겠습니다.

가 장 큰 차이점은 개별(peer) 클래스로딩 구현이 도입된 것입니다. JRE의 기본 계층적 모델과 달리, 이 방식은 visibility 문제점을 해결하였습니다. JBoss가 이 방식을 최초로 시도한 것은 아닙니다. 예를들어 OSGi 스펙이나 기타 많은 실험적 프로젝트들에서 이 방식을 시도한 사례가 있습니다. 하지만 실제 운용 가능한 제품에서 이 방식을 구현한것은 JBoss가 최초입니다. 이것은 JRE 자체에 내제하고 있는 수많은 심각한 동시성 이슈들을 발견하게 만들어준 최초 구현이었다는 것을 의미합니다.

첫번째 주요 이슈는 데드락 문제였습니다. 클래스로딩 규칙은 두개의 클래스로딩 요청이 동일한 클래스로더에서 동시에 이루어져서는 안된다는 제약을 가지고 있습니다. 이것이 추가적인 락킹 동작을 필요로 하기 때문입니다. 개별 위임 모델 내에서 이것이 제대로 동작하지 않는 경우 데드락 이슈를 발생시킬 수 있습니다. 게다가 실제 JRE가 락킹을 (대부분의 유명한 자바 버그들을 일으키는) 문서화되지 않은 방법을 통해서 강제로 수행하기 때문에, 이것을 해결하기가 예상보다 훨씬 어렵다는 것이 밝혀졌습니다. 이 이슈를 해결하기 위한 추가 작업 이후에도, 또다른 동시성 이슈들이 JRE 내부의 보다 깊숙한 곳에서 발견되었습니다. 두번째 이슈는 JRE 내부의 클래스 검증 코드들을 완전하게 재작성함으로써 해결하였지만, 첫번째 이슈는 이 글을 작성하는 지금까지 여전히 풀리지 않은 상태로 남아있었습니다. Java7에서 이 문제를 해결하기 위한 계획이 세워져 있기는 하지만 JBoss는 이 버그들이 해결될때까지 기다릴 수 없었기 때문에, 추가적인 복잡성을 감안하고서도 UnifiedClassLoader를 대신 사용함으로써 이 문제를 해결하였습니다.

최초의 UnifiedClassLoader는 개별 클래스로더들의 단일 저장소 형태로 구현되었습니다. 각각의 클래스로더는 클래스로딩 요청을 레포지토리를 통해 위임함으로써 다른 클래스로더들이 로딩한 클래스들을 볼 수 있었습니다. 이후에 HierarchicalLoaderRepository (SIC!) 가 소개되었는데, 이것은 클래스로더를 고립시키기 원하는 사용자들에게 다시금 해당 기능을 사용할 수 있도록 해 주었습니다. 사실 이것은 나중에 추가된 기능이어서, 실제 세부 구현은 깔끔하지 못합니다.

진행 도중 최초 UnifiedClassLoader가 jar 파일당 하나의 클래스로더를 생성하는 것이 비효율적일 뿐 아니라, package private 문제를 발생시킨다는 것이 발견되었습니다. 따라서 최 상위 레벨 디플로이먼트 당 하나의 클래스로더를 생성하는 방식으로 변경되었습니다.

사용자는 다른 클래스로더 구현들을 레포지토리에 등록할 수 있지만, 그것들은 개별 클래스로더들의 위임 구조 내에 완벽한 형대로 참여할 수 없습니다. UnifiedClassLoader는 그것들을 완정한 형태의 개별 클래스로더로 사용할 수 있지만, 반대로는 적용되지 않습니다.

기 본적으로, 웹 어플리케이션들 또한 클래스로딩을 위해 UnifiedClassLoader를 사용합니다. 그러나 이것은 사용자가 원하는 클래스로딩 모델을 선택하도록 하는 설정 옵션을 통해서 Tomcat 클래스로더를 기본값으로 사용하도록 변경되었습니다. 대부분의 웹 개발자들은 자신들의 웹 어플리케이션이 다른 클래스들로부터 고립되는 것을 기대합니다.
 
UnifiedClassLoader 와 관련하여 해결되지 않는 주요 이슈중 하나는 클래스로딩 의존성(dependency)입니다. 이 아이디어는 A라는 어플리케이션이 B라는 다른 어플리케이션의 클래스들을 사용한다고 했을때, B가 리디플로이 되는 시점에 시스템이 A를 리디플로이해야한다는 것을 알야야 한다는 것입니다. 그렇지 않으면, A 어플리케이션은 더 이상 사용되지 안는 구 버전의 클래스들을 레퍼런싱 할 것입니다. 실제로 사용자의 별도 설정 없이도 이것이 동작하도록 하기 위한 두 가지 접근방법이 시도되었지만, 두 방법 모두 제대로 동작하지 않아 현재는 모두 폐기되었습니다.


JBoss-5.x - The New ClassLoader

위키 상의 'The new classloader' 아티클에 보다 자세한 사항이 설명되어 있습니다. UnifiedClassLoader와 마찬가지로, 그것의 목적은 이전 구현 버전을 사용한 경우에 나타나는 문제점들을 해결하고, 추가된 몇가지 요구사항들을 해결하기 위함입니다. UnifedClassLoader와는 다르게, new classloader는 실제로는 잘 사용되지 않는 한가지 예외사항을 제외하면  완전한 하위 호환성을 가지고 있습니다. 이것은 JBoss3/4에서 모든 클래스로딩 설정들이 여전히 새로운 구현과 잘 동작한다는것을 의미합니다. 사실, 디플로이어들이 다시 구현됨에 따라 몇가지 기본 설정들이 이동되었음에도 불구하고, 그것이 기본적으로 구 버전과 동일한 동작을 보이도록 설정되었는지에 대한 추가 확인 작업이 있었습니다.

 
new classloader는 UnifiedClassLoader와 많은 부분에서 디자인및 구현 방식을 공유하고 있지만, 몇가지 사항에서 개선이 이루어졌습니다.

    * 더이상 JMX상에 의존성이 없기때문에, 어떠한 환경에서도 standalone으로 사용될 수 있습니다.
    * 사용자는 개별 클래스로더 위임 모델을 구현하기 위해 필요한 세부 지식을 알지 못하더라도 사용자 커스텀 클래스로더 정책을 구현할 수 있습니다.
    *  사용자 클래스로더가 클래스로딩을 위임하는 다른 클래스로더 상에서 보다 많은 제어권을 갖게 됩니다.
    * 사용자는 다른 클래스로더가 볼수 있는 클래스들에 보다 많은 제어권을 갖게 됩니다.
   * 계층적 레포지토리들을 도메인(domain)으로 보다 명확하게 재구현하였으며, 이제 1레벨 이상으로 확장(상속?) 할수 있습니다.

기 본 클래스로더 정책은 리소스 위치를 찾기 위해서 새로운 JBoss VFS를 사용합니다. 이렇게 변경하게 된 주요 목적는 파일 락킹 문제나(윈도우의 경우), 파일 핸들 누수leak(리눅스의 경우) 같은 문제점들을 한 지점에서 통합하여 다루기 위한 것입니다. 이전에는 UnifiedClassLoader들은 URLClassLoader를 상속받았는데 이 클래스는 사용자가 부주의하게 사용하는 경우 jar 파일 레퍼런스 누수를 발생시킬 수 있었지만, Sun에서는 이 문제를 해결하는 것을 거부하였습니다. 또다른 변경 동기는 embedded jar 내부에 있는 리소스들을 사용자가 URL을 사용하여 표현할 수 없어서, 이 경우 사용자가 직접 jar 파일을 임시 디렉토리에 풀어야 했기 때문입니다.

new classloader 구현의 최 상단에는 새로운 레이어가 있는데, 이 레이어에는 클래스로딩 의존성이 도입되었고, 클래스 어노테이션 스캐닝 같은 헬퍼 유틸리티들을 추가하였습니다. 이 레이어는 여러분이 OSGi 내에서 찾을수 있는 versioning이나 사용자가 직접 의존성을 기술하는 것 같은 보다 복잡한 작업에 "write your own dependency"를 위한 기능 같은 모든 것들이 포함되어 있습니다.

새로운 레이어는 메타모델을 사용하므로, 사용자는 클래스로더 구현 세부사항을 알 필요가 없습니다. 구버전 클래스로더 설정은 자동으로 이 메타모델에 맵핑되거나, META-INF/jboss-classloading.xml파일을 통해 사용자가 보다 직접적으로 사용할 수 있습니다. 우리의 OSGi 구현이 준비되면, 사용자는 또한 OSGi manifest 헤더를 사용하여, 사용자 클래스로딩 의존성을 정의할 수 있습니다.

 
마지막으로 클래스로더 구현은 실제로 새로운 JBoss 디플로이어 인프라 내에서 단지 선택 가능한 사항입니다. 원칙적으로 (비록 우리가 전문가가 아닌 경우 추천하지는 않지만) 그것은 사용자의 선택에 따라 어떠한 클래스로더 구현으로 교체 될 수 있습니다. 하지만 대부분의 경우 new classloader 구현이 사용자가 필요로하는 모든 기능들을 어느정도 충족시킬수 있을 것입니다.

- 이후 발전 방향
 

이 섹션은 물론 필자의 예상입니다.
Java 7은 클래스로딩과 관련하여 두가지 흥미로운 기능을 소개하고 있습니다.

    * 위에서 언급된 적절한 동시 클래스로딩을 하기 위한 기능, 이것은 락킹 문제들과 관련 문제점들을 제거할것입니다.
    * JSR294의 "super package" 모듈화


우리는  (과거와 마찬가지로) 클래스로더의 새로운 기능들이 어떻게 사용되는지 에 대한, 보다 많은 경험이 축적됨에 따라서, 클래스로더 구현을 보다 더 진보시킬수 있다고 기대합니다.

크리에이티브 커먼즈 라이센스
Creative Commons License
2009/05/28 18:00 2009/05/28 18:00
http://www.javapattern.info/trackback/251