SSISO Community

시소당

J2EE ClassLoader 우선 순위 및 접근방식

제목 : Re: J2EE ClassLoader 우선 순위 및 접근방식
글쓴이: 김진호(alpajino) 2003/04/12 18:04:16 조회수:213 줄수:102

위의 싱글턴 문제의 경우, Application 서버상의 정확한 클래스 로딩 구조에
대해서 모르기 때문에 발생한 문제로
위의 경우뿐만 아니라..
대부분의 EJB, Web App 관련 에러가 Classloader 문제에 기인합니다.

예) 소스를 수정 했는데...클래스가 안바뀝니다.
디플로이는 잘 됐다구 나오는데.. 돌려 보면 해당 클래스를 못찾아요...
값이 맞다가 안맞다가 하네요....등등...


개인적인 소견으로
Application Server의 classloader에 대해서 정확히 안다면
해당 에러의 많은 부분을 줄일 수 있고, 또한 대부분의
응용프로그램을 실행 및 배치 시킬수 있다고 생각됩니다.

그래서 이번 기회에 한번 J2EE 상의 클래스 로딩 구조에 대해서 정리 해보겠습니다.



먼저 위의 그림이 J2EE 1.3 상의 클래스 로딩 구조 입니다. 예전 버전(1.2.2)에선 이부분이
명확하지가 않아서 밴더마다 조금씩 차이가 있었는데..1.3 오면서 위와 같이 표준이 정해졌습니다.

보실때 굵은선으로 구별되는 것 각각이 자기만의 클래스로더를 가지고 있다고 생각하시면 됩니다.
점선의 경우 클래스를 공유한다고 생각하시면 되고요.

즉 JVM은 기본 API에 대한 클래스를 로딩 하고
Application 서버(Weblogic, Websphere, 제우스등..)은 기본 JVM 위에서 자신만의 클래스를 로딩하고
그 다음에
개발자가 개발한 EJB, WAR, EAR들이 각자의 클래스 구조를 가지고 그 위에 올라가는 거죠.
(각각의 EJB,EJB,EJB들은 각각의 클래스 로더를 가짐)



자..그럼.. 그렇게 올라간 각 부분이 클래스를 접근하는 경로를 보겠습니다.
간단하게 그림에서 위에서 아래로는 접근할수 있고, 옆으로 분리된 상태는 안된다고 보시면 됩니다.

1. 해당 EJB의 경우 Application 서버가 구동시 잡은 Classpath상의 모든 클래스와
JVM에 접근 할 수 있다. 다른 EJB 및 옆의 WAR/EAR 상의 클래스 접근 불가..

2. 해당 WAR의 경우 Application 서버가 구동시 잡은 Classpath상의 모든 클래스와
JVM에 접근 할 수 있다. 다른 WAR 및 옆의 WAR/EAR 상의 클래스 접근 불가..

3. 해당 EAR의 경우 좀 다르게..해당 내부의 WAR(들) 및 EJB(들) 상의 클래스를 다 접근 할수 있다

4. 그리고 Application 서버가 구동시 잡은 Classpath상의 모든 클래스와
JVM에 접근 할 수 있다. 다른 EAR 및 옆의 WAR/EJB 상의 클래스 접근 불가..



그럼 이렇게 접근하는 클래스가 중복되었을 경우 어떻게 되는가?
자바에서 클래서 로딩 규칙은
동일한 클래스가 클래스패스에 각가 잡혀 있을경우 먼저 올라간 놈이 장땡(?) 이다.
J2EE상의 클래스 로딩 우선 순위는 그림과 같이 밑으로 갈수록 높다.

1 순위 : 당연히 JVM 상의 기본 클래스들..(API)들이다.

2 순위 : Application 서버가 구동시 잡는 각종 클래스 패스상의 클래스들

동률 3 순위 : EJB, WAR, EAR은 같은 레벨의 클래스 우선순위를 가진다.
그래서 같은 이름(패키지가 같고, 클래스명이 동일한)의 클래스가
여러 컴포넌트(EJB, WAR, EAR...) 상에 올라 갈수 있다.
그리고 따로 따로 동작한다.

기타 EAR 상에서는 EJB가 우선이고 WAR 파일이 나중이다.


정리 하자면
com.tebss.test.AClass 라는 클래스가 있고
이 클래스가 그림에서 아랫부분(부모) 클래스로드에서 로딩되었다면.. 그다음에 오는
동일명 클래스(패키지가 같고, 클래스명이 동일한)는 절대 클래스가 올라갈 수 없습니다.

하지만 동일 레벨의 클래스로더들(EJB, WAR, EAR) 상에서는 동일명 클래스가
로딩될 수 있습니다.

그리고 EAR 상에서는 EJB 부분이 먼저고, WAR 부분이 나중입니다.

자..그럼 위의 클래스로더 구조를 가지고 위의 싱글턴 문제를 함 보겠습니다.



위의 그림 상태가 위에서 최초의 싱글턴 구현 방식이였습니다.
보시다 시피 EJB마다 동일한 싱글턴 클래스가 있기 때문에
각자 클래스로더 상에 올라갔고..따로따로..돌아 간거죠...
(물론 비지니스 로직에 의해서 위와 같이 싱글턴을 구현할 수 도 있음)



위의 그림이 시스템 패스상에 싱글턴 클래스를 걸어준 형태입니다.
이경우 설령 그림처럼..EJB, WAR,EAR 상에 동일한 싱글턴 클래스가 있더라도
실제 클래스로더상에 올라가는 놈은 D 번 한놈밖에 없죠.

그리고 각 컴포넌트 부분에서 접근할때도.. 그 한놈에게만 접근하게 되는거죠.
그래서 무사히 싱글턴하게 되는거죠...




Download classloader1.gif (7537 Bytes) classloader1.gif (7537 Bytes)
Download classloader2.gif (10201 Bytes) classloader2.gif (10201 Bytes)
Download classloader3.gif (11607 Bytes) classloader3.gif (11607 Bytes)
Download classloader4.gif (8504 Bytes) classloader4.gif (8504 Bytes)
Download classloader5.gif (9985 Bytes) classloader5.gif (9985 Bytes)
제목 : Re: [추가질문] 이야기가 조금 샙니다만..
글쓴이: 신상재(bomber) 2003/04/13 14:17:35 조회수:54 줄수:36

요즘들어 김진호님 글이 제가 궁금해 하는 부분을 많이 해결해주셔서
개인적으로 감사드립니다. m(_ _)m 꾸벅..

앞 글 중 j2ee class loader 계층구조를 보면서
예전부터 궁금한 것을 여쭤보려고 합니다.

하나의 ear의 경우 class를 공유한다고 되어있는데
이 부분에 조금 더 자세한 설명을 부탁드립니다.

왜냐면..
제가 알기로는
ear는 war와 jar들로 구성이 되는데
같은 ear 안에 있다고 하더라도
다른 jar안에 묶인 class는 jar 끼리 접근을 하지 못해서
(단, class loader가 뒤에 뜨는 war는 모든 jar의 class에 접근가능하고...)
manifest file에서 class path 정보를
각 jar 항목마다 기재해주는 것으로 알고 있습니다.
그러니.. 엄격히 말하자면 공유... 는 아닌 것 같아서요..
이 부분은 client view class가 담긴
client-jar에 관한 j2ee, ejb 스펙을 보니 그렇게 나오더군요.
공유가 된다면 굳이 manifest file에서 client jar를 써줄 필요도 없을 것 같아서요..
그리고 만약 공유된다면 manifest file을 쓰는 "reference" 방식이 아닌
각 jar에 필요한 공통 class 들을 같이 packaging하는 "include" 방식을 쓰는 경우
같은 이름의 class 들의 충돌문제가 발생할 것도 같습니다.
제가 제대로 알고 정리가 된 것인지.. 틀렸으면 지적 부탁드립니다.

제가 이 부분을 확인하고 싶은 이유는...
만약 ear 안에 war 여러개, jar 여러개를 넣게되는 경우,
class 참조 관계가 어떻게 될지 혼란이 되어서 그렇습니다.

이야기가 client jar 이야기까지 이어져 버렸는데
김진호씨가 쓰신 다른 관련 글 잘 읽어보았구요...
확인 차 관련글로 재질문 드립니다.

좋은 주말 되세요.
제목 : Weblogic 상 EAR ClassLoader 구조
글쓴이: 김진호(alpajino) 2003/04/15 06:09:54 조회수:89 줄수:118

EAR 내부적인 클래스 로딩 부분은 스팩이나 Blueprint상에 명확하게 정의되어 있지는
않습니다.

그래서 위에 글에서 설명할 때도
"클래스를 공유한다고 생각하시면 되고요" 라고 말씀드린겁니다.

여기서 공유라는 단어를 제가 썼는데.. 사실 클래스 로딩에선 공유라는건 없죠.
단순히 종속내지는 부모자식관계(Parent/Child)의 계층형 구조인거죠.
하지만 EAR 관련 밴더 문서를 살펴 보면, 이 아저씨들도 Share 라는 단어를 쓰고있죠 ^^;

자, 그럼 여기서 위에서 말씀하신 스펙상에서의 manifest file를 통한 class path 설정 부분과
제가 공유(share)라고 얘기하는 부분에 대해서 함 써 보겠습니다.

먼저 용어를 정리할게 있는데,

Application Client라는 부분과 Client View Classes라는 부분입니다.

Application Client라는 부분은 스펙에서도 한 쳅터(9장)를 턱..하니 차지하고 있는 놈으로
스펙에서는 다음과 같이 정의 하죠.

-. 자신의 자바 가상머신위에서 동작하는 클라이언트 프로그램
-. 메인 함수호출로 시작해서 가상머신이 끝날때까지 작동
-. 중량의 컴포넌트로 서비스중 보안과 배치 서비스만 제공
-. 대표적인 예로 애플릿, 스윙 어플리케이션, 웹스타트등등.....


그리고
Client View Classes(ejb-client.jar)
-. 한 EJB 컴포넌트가 다른 EJB 및 기타 컴포넌트들에 클라이언트가 될 경우를 위해,
관련된 클래스만 모아 놓은 일종의 공통클래스, 인터페이스 클래스

-. 기본적으로 Remote , Home 인터페이스 및 Primary key class (엔티티의 경우)를 포함하고,
위의 인터페이스, 클래스의 함수 시그니쳐상에 정의된 클래스를 포함(리턴값,인자값, 예외클래스등)
하고 있는거라고 할수 있습니다.


위에서 스펙상에 있는 manifest 부분을 말씀하시는걸 보니 전자 보다는 후자쪽(ejb-client.jar)
관련 부분인거 같군요.

이부분은 J2EE 1.3 스펙의 8.1.1.2 Dependencies라는 항목으로 정의되어 있습니다.
스펙에 니와있는 예제를 보면...

app1.ear:
META-INF/application.xml
ejb1.jar Class-Path: util.jar
ejb2.jar Class-Path: util.jar
util.jar


뭐.. 내용은....
"니가 유틸리티성 클래스를 모아서 util.jar를 만들었고, 고걸 공통으로 쓰는 ejb1이라는 눔과
ejb2라는 눔을 똘똘마리로.. 묶어서 올리려구 허면....
위에처럼 해당 모듈(ejb.jar등..)의 manifest 상에 클래스 패스를 잡아 주면 된다이...."
이 얘긴데... 맞죠... 아니 스펙에서 required 하니까... 따라야죠..^^;

그런데..요 얘기로 ejb1, ejb2가 완전히 다른 클래스로더를 사용하는 걸로 보기는 어렵습니다.

단순히 이 부분은 J2EE 모듈(또는 컴포넌트)들 간에 의존성이 있을 경우 참조 방법 내지 ,
어떻게 패키징 하는것이 좀더 portable 하는냐는 부분에 맞춰진거지.. 클래서로더 문제랑은 별개입니다
(Pakaging 관련 참조 : http://developer.java.sun.com/developer/technicalArticles/J2EE/build/ )


실제 밴더(Weblogic)에서 구현한 EAR상에서의 ClassLoader는 아래 그림처럼 되어 있습니다.



그림에서 처럼 EAR 상의 Root classloader는 각 EJB 파일들이고, 그 위에 WAR들이 각기 올라가는 형태입니다.
이때 각 EJB들은 클래스를 공유(?)하는거죠....
그래서 특정 EJB 를 호출한다고 해서 해당 EJB의 홈 및 리모트 인터페이스를 꼭가지고 있을 필요가 없이
걍... EAR 파일 내부에 해당 EJB.jar 가 있으면 해당 홈 및 리모트 인터페이스를 땡겨다가 쓸수 있는거죠...

물론 말씀하신 내용중에서 이름 충돌부분은 발생합니다. 같은 클래스가 여러 jar파일에 있을 경우는 제일 먼저 올라간
좀 이외에 것들은 로딩되지 않습니다.(당연한가???)

그리고 스팩상의 방식으로 manifest상에 클래스 패스를 설정해서 패키징한 것도 적용됩니다.

그럼, 만약에... A라는 클래스가 ejb1.jar안에도 있고, util.jar안에도 있다..
그리고 패키징 방식은 아래와 같다면 어떤 A 클래스가 올라갈까요?

app1.ear:
META-INF/application.xml
ejb1.jar Class-Path: util.jar
util.jar

ejb1 내부에 있는 게 먼저 설정됩니다.


위와 같이 클래스 로더를 잡았을때의 장점으로는
EAR내부에서는 EJB 호출시 Call by reference가 가능하고
(가장 큰 이유죠, 팬타스틱이라는 단어를 사용하면서 성능이 낳아진다더군요..^^;),
해당 모듈이 EAR 상에 있으면, 해당 모듈을 호출하는 놈들이 꼭 해당 모듈(컴포넌트)의 인터페이스를
가지고 있을 필요없고, 웹 모듈만 독립적으로 다시 재배치될수 있고 등등.....라고 애기하는군요.

물론 이런 방식은 완전히 스펙에 부합되는건 아니죠.
하지만 성능땜시... 물론 스팩상에서 요구하는 패키징 관련은 준수하고 있죠..
그래서 이 제품이 j2ee 1.3 Certi를 받은거 겠지만요...^^;


쓰다 보니 중언부언만 늘어난거 같군요.

하여튼 결론은
EAR관련 클래스 로더 부분은 밴더 종속적인 부분이 많다. 스펙에도 명확히 정의되어 있지 않다.
고로 자신이 사용하는 제품의 문서를 참조해서, 최적의 패키징 정책을 가져가야한다.(또 당연한 얘긴가..^^;)

참.. 님께서 사용하고 있는 제품이 Weblogic 제품이라면 제가 시간 나는데로 함 정리 해보죠...

Weblogic쪽에선 이 부분에 많은 기능을 첨부해 놓았거든요
뭐..클래스 로딩 순서를 임의로 구성하게 한다든지, 특정 클래스만 재배치가능하게 한다든지...
아님 App-INF라는 디렉토리를 설정해서 classes/lib라를 디렉토리를 구성하게 한다든지...
ejb-client.jar 파일을 자동생성하는 부분등.....

만약에 웹스피어 쪽 전문가가 계시면 웹스피어쪽 EAR 구조를 좀 올려주시면,
함 비교해 보면 재미있을거 같네요..
다른 벤더도 좋구요...

그럼...

Download ejbclassload.gif (3585 Bytes) ejbclassload.gif (3585 Bytes)

 

출처 : http://javaservice.net/~java/bbs/read.cgi?m=resource&b=qna2&c=r_p&n=1050138256&d=n#1050138256

574 view

4.0 stars