문제

여기에 제가 가동하는 문제가 있습니다. Java 1.3에서 실행되고 외부 API (예 : Myapi v1.0)를 사용하는 거대한 레거시 응용 프로그램이 있습니다. MyAPI 1.0의 정확한 구현은 앱에서 사용하는 클래스 경로 어딘가에 있습니다. 해당 앱이 외부 코드 (일부 종류의 플러그인 메커니즘)를 사용할 수있는 메커니즘도 있습니다. 이제 Myapi v2.0 (v1.0과 100% 뒤로 호환되지 않음)을 사용하는 다른 Java 라이브러리 (Mylib.jar)가 있으며 해당 플러그인 메커니즘을 사용하여 원래 앱에서 사용해야합니다. 그래서 나는 어떻게 든 동일한 API의 두 가지 (호환되지 않는!) 버전이 함께 작동하도록해야합니다. 특히 API 클래스가 MyLib.jar 클래스에서 호출 될 때 MyAPI v2.0을 사용하고 다른 모든 경우에 MyAPI 1.0을 사용하고 싶습니다.

Myapi 1.0은 클래스 경로에 있으므로 기본적으로 사용됩니다. 괜찮습니다. Myapi 2.0에서 클래스를로드하기 위해 나만의 클래스 로더 버전을 만들 수 있습니다. 하지만 어떻게 모든 것을 함께 맞출 수 있습니까? 질문:

  1. mylib.jar 객체는 Myapi 2.0의 클래스 인스턴스를 많이 인스턴스화합니다 (!). 이것은 반사를 통해 이러한 모든 인스턴스화를해야한다는 것을 의미합니까 (내 클래스 로더 지정)? 그것은 일의 지옥입니다!

  2. MyAPI 2.0 객체 중 일부가 인스턴스화되고 MyAPI의 다른 개체를 내부적으로 인스턴스화하면 어떤 클래스 로더를 사용합니까? 내 클래스 로더 또는 기본 로더를 사용합니까?

  3. 일반적으로 내 접근 방식이 합리적으로 들리나요? 더 좋은 방법이 있습니까?

도움이 되었습니까?

해결책

두 번째 질문에 대답하면서 시작하자 : 일부 클래스에서 다른 클래스로 참조 할 때 원래 클래스를로드 한 동일한 클래스 로더로로드됩니다 (물론 클래스 로더가 클래스를 찾는 데 성공하지 않는 한, 그것은 그것의 클래스를 위임 할 것입니다. 부모 클래스 로더).

그 말에 따르면, 왜 당신의 전체 mylib.jar가 사용자 정의 클래스 로더로로드되지 않는지, 그리고 새로운 버전의 API를 정기적으로 언급 할 수 있습니다. 그렇지 않으면 객체 유형과 반사를 끝까지 작업해야하기 때문에 문제가 있습니다.

다른 팁

클래스 로더에주의해야합니다. 당신이 제안한 일을한다면, 당신은 Myapi 2.0에 클래스 로더를 사용할 때에도 거의 항상 Myapi 1.0을 끝낼 것입니다. 그 이유는 클래스 로더를 사용하여 클래스를로드하는 방법입니다. 클래스는 항상 부모 클래스 로더에서 먼저로드됩니다.

"클래스 로더 클래스는 클래스와 리소스를 검색하기 위해 대표 모델을 사용합니다. 각 클래스 로더 인스턴스는 관련 상위 클래스 로더가 있습니다. 클래스 또는 리소스를 찾도록 요청하면 클래스 로더 인스턴스는 클래스 또는 리소스 검색을 부모에게 위임합니다. 클래스 로더 클래스 또는 리소스 자체를 찾기 전에 클래스 로더. "부트 스트랩 클래스 로더"라고하는 가상 머신의 내장 클래스 로더는 자체가 부모가 없지만 클래스 로더 인스턴스의 부모 역할을 할 수 있습니다. "http://java.sun.com/javase/6/docs/api/java/lang/classloader.html)

두 API를 올바르게 분리하려면 2 개의 클래스 로더 (또는 기본 응용 프로그램 외에 2 개)가 필요합니다.

Parent - System classloader
  |- Classloader1 - Used to load MyAPI 1.0
  |- Classloader2 - Used to load MyAPI 2.0

이제 당신의 질문에. 아마도 원하는 것은 API를 사용하는 대부분의 논리를 클래스 로더로 이동하는 것입니다. MyAPI 1.0/2.0 외에도이를 사용하는 응용 프로그램의 일부를로드해야합니다. 그런 다음 상위 응용 프로그램은 API를 사용하는 메소드를 호출해야합니다. 이렇게하면 응용 프로그램을 시작하기 위해 단일 반사 호출을 만들고 해당 응용 프로그램 내부의 모든 것이 표준 참조를 사용합니다.

반사없이 멋진 클래스 로더 로이 작업을 수행 할 수 있습니다.

기본적으로 클래스 로더는 "로딩 클래스 가이 JAR에서 나온 경우 클래스 경로 B에서로드하고, 그렇지 않으면 메인 클래스 로더를 사용하십시오"라고 말해야합니다.

그것은 그것보다 조금 더 복잡하지만, 그 아이디어에서 시작하면 그것을 해결할 것입니다.

이것은 합리적으로 들립니다. [loadclass의 API javadoc] [1]에서 :

"지정된 이진 이름으로 클래스를로드합니다.이 메소드의 기본 구현은 다음 순서로 클래스를 검색합니다. findloadedClass (String)를 호출하여 클래스가 이미로드되었는지 확인하십시오.

부모 클래스 로더에서로드 클래스 메소드를 호출하십시오. 부모가 NULL이면 가상 머신에 내장 된 클래스 로더가 사용됩니다.

FindClass (String) 메소드를 호출하여 클래스를 찾으십시오. "

CL1이 MyAPI1 용 인 경우 Cl2는 MyAPI2 용이고 Cl3은 MyLib에 대한 것입니다. CL3, CL2, CL1 순서대로 확인하기를 원하는 것처럼 들립니다. 위의 인용문에서 (부모가 먼저 확인했듯이) CL1에 부모 CL2가 있고 CL2가 부모 CL3을 갖기를 원합니다. 상위 클래스 로더가있는 생성자가 보호되므로 부모가 적절하게 설정된 URL 클래스 로더를 사용해야합니다.

같은 것

URLCLassLoader cl3 = new URLClassLoader(new URL[]{ path to MyLib});
URLCLassLoader cl2 = new URLClassLoader(new URL[]{ path to API2}, cl3);
URLCLassLoader cl1 = new URLClassLoader(new URL[]{ path to API1}, cl2);

그런 다음 어디에나 CL1을 사용하십시오.

[1]: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/classloader.html#loadcass(java.lang.string, 부울)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top