URLClassLoader
을 사용하여 parent: null
을 전달하고 리플렉션을 사용하여 멤버를 인스턴스화하여 클래스 경로 및 나머지 버전에서 하나의 버전을로드 할 수 있습니다. 내가 this Git repo이에 대한 POC를 만들어
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
public class ParentLastClassLoader extends ClassLoader {
private ClassLoader parentClassLoader;
private URLClassLoader noParentClassLoader;
public ParentLastClassLoader(URL[] urls, ClassLoader parent) {
super(parent);
this.noParentClassLoader = new URLClassLoader(urls, null);
}
public ParentLastClassLoader(URL[] urls) {
super(Thread.currentThread().getContextClassLoader());
this.noParentClassLoader = new URLClassLoader(urls, null);
}
public ParentLastClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
super(parent);
this.noParentClassLoader = new URLClassLoader(urls, null, factory);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
try {
// resolve using child class loader
return noParentClassLoader.loadClass(name);
} catch (ClassNotFoundException ex) {
// resolve using parent class loader
return super.loadClass(name, resolve);
}
}
}
:
대안처럼 그 보일 수 있습니다 here을 설명 접근 방식을 기반으로 사용자 정의 클래스 로더를 사용하는 것입니다. 자세한 내용은 README.md에 있습니다.
POC 내용은 여러 버전 (프로젝트 V1, V2, V3) 다음 조각으로 구성된 도서관이 점을 고려
:이 인터페이스를 가지고
이
우리가 원하는 우리의 라이브러리 :
0,123,636 :에 의해 구현된다
public interface Core {
String getVersion();
String getDependencyVersion();
}
3,975,142,674,234,255,819,633,210 다른 동일한 라이브러리의 클래스를 사용
:
package sample.multiversion;
public class Utility {
public String getVersion() {
return "core-v1";
}
}
마지막
라이브러리 (프로젝트 V1, V2, V3)는 (프로젝트 v1dep, v2dep, v3dep)을 포함하는 종속성을 가지고
package sample.multiversion.deps;
public class CoreDependency {
public String getVersion() {
return "core-dep-v1";
}
}
그리고 우리는 모두 세 가지 버전을로드 할 수
파일에서
- V3 - - 파일
- V2에서 -
- V1 클래스 경로
의 코드는 다음과 같습니다
// multiple versions of the same library to be used at the same time
URL v1 = Paths.get("./../v1/build/libs/v1.jar").toUri().toURL();
URL v2 = Paths.get("./../v2/build/libs/v2.jar").toUri().toURL();
// library dependencies
URL v1Dep = Paths.get("./../v1dep/build/libs/v1dep.jar").toUri().toURL();
URL v2Dep = Paths.get("./../v2dep/build/libs/v2dep.jar").toUri().toURL();
/**
* version 1 and 2 loaders
* - these loaders do not use the root loader - Thread.currentThread().getContextClassLoader()
* - using the root loader new URLClassLoader(new URL[]{v1, v1Dep}, Thread.currentThread().getContextClassLoader());
* will solve any class with the root loader and if no class is found then the child loader will be used
* - because version 3 is loaded from classpath, the root loader should not be used to load version 1 and 2
* - null needs to be passed to parent argument, else will not work
*/
URLClassLoader loaderV1 = new URLClassLoader(new URL[]{v1, v1Dep}, null);
URLClassLoader loaderV2 = new URLClassLoader(new URL[]{v2, v2Dep}, null);
/**
* Use custom class loader for loading classes first from children and last from parent
*/
ParentLastClassLoader loaderV1Alt = new ParentLastClassLoader(new URL[]{v1, v1Dep});
ParentLastClassLoader loaderV2Alt = new ParentLastClassLoader(new URL[]{v2, v2Dep});
ParentLastClassLoader loaderV3Alt = new ParentLastClassLoader(new URL[]{});
// get class from loader
Class<?> coreV1Class = loaderV1.loadClass("sample.multiversion.ImportantCore");
Class<?> coreV2Class = loaderV2.loadClass("sample.multiversion.ImportantCore");
// get class from loader - custom version
Class<?> coreV1AltClass = loaderV1Alt.loadClass("sample.multiversion.ImportantCore");
Class<?> coreV2AltClass = loaderV2Alt.loadClass("sample.multiversion.ImportantCore");
Class<?> coreV3AltClass = loaderV3Alt.loadClass("sample.multiversion.ImportantCore");
// create class instance
Object coreV1Instance = coreV1Class.newInstance();
Object coreV2Instance = coreV2Class.newInstance();
// create class instance - obtained from custom class loader
Object coreV1AltInstance = coreV1AltClass.newInstance();
Object coreV2AltInstance = coreV2AltClass.newInstance();
// note that this is loaded from classpath
Core coreV3Instance = new ImportantCore();
Core coreV3AltInstance = (Core)coreV3AltClass.newInstance();
// get version
String v1Str = (String) coreV1Class.getMethod("getVersion").invoke(coreV1Instance);
String v2Str = (String) coreV2Class.getMethod("getVersion").invoke(coreV2Instance);
String v1AltStr = (String) coreV1AltClass.getMethod("getVersion").invoke(coreV1AltInstance);
String v2AltStr = (String) coreV2AltClass.getMethod("getVersion").invoke(coreV2AltInstance);
String v3Str = coreV3Instance.getVersion();
String v3AltStr = coreV3AltInstance.getVersion();
// get version of dependency
String v1DepStr = (String) coreV1Class.getMethod("getDependencyVersion").invoke(coreV1Instance);
String v2DepStr = (String) coreV2Class.getMethod("getDependencyVersion").invoke(coreV2Instance);
String v1AltDepStr = (String) coreV1AltClass.getMethod("getDependencyVersion").invoke(coreV1AltInstance);
String v2AltDepStr = (String) coreV2AltClass.getMethod("getDependencyVersion").invoke(coreV2AltInstance);
String v3DepStr = coreV3Instance.getDependencyVersion();
String v3AltDepStr = coreV3AltInstance.getDependencyVersion();
System.out.println(String.format("V1 loader :: version = '%s' :: dependency_version = '%s'", v1Str, v1DepStr));
System.out.println(String.format("V2 loader :: version = '%s' :: dependency_version = '%s'", v2Str, v2DepStr));
System.out.println(String.format("V3 loader :: version = '%s' :: dependency_version = '%s'", v3Str, v3DepStr));
System.out.println(String.format("V1 custom loader :: version = '%s' :: dependency_version = '%s'", v1AltStr, v1AltDepStr));
System.out.println(String.format("V2 custom loader :: version = '%s' :: dependency_version = '%s'", v2AltStr, v2AltDepStr));
System.out.println(String.format("V3 custom loader :: version = '%s' :: dependency_version = '%s'", v3AltStr, v3AltDepStr));
참고 :Core
인터페이스는 다른 프로젝트의 일부가 될 수있다 이것은 v1, v2, v3
프로젝트에 의해 사용되어 우리가 새로 생성 된 인스턴스를 캐스팅하고 타입 안전 방식으로 작업 할 수있게합니다. 그러나 이것은 매번 할 수 없을 수도 있습니다.
나는 잘 모르겠다.하지만 나는 문제가 있기 때문에 업데이트를 유지하기를 원한다. 미안 해요! – Zorglube