fla*_*kes 8 java legacy static classloader
免责声明:鉴于这个问题,这可能不是最佳解决方案,但我很好奇如何实现这一实施.
问题我正在尝试处理一些遗留代码,这些代码的单例定义如下:
public class LegacySingleton {
private static Boolean value;
public static void setup(boolean v) {
if (value != null) {
throw new RuntimeException("Already Set up");
}
value = v;
System.out.println("Setup complete");
}
public static void teardown() {
value = null;
System.out.println("Teardown complete");
}
public static boolean getValue() {
return value;
}
}
Run Code Online (Sandbox Code Playgroud)
我无法更改此设计,并且在整个代码库中大量使用该类.此单例返回的值可以极大地改变代码的功能.例如:
public class LegacyRequestHandler {
public void handleRequest() {
if (LegacySingleton.getValue()) {
System.out.println("Path A");
} else {
System.out.println("Path B");
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我想要代码Path A,那么我必须以LegacySingleton特定的方式初始化.如果我想接受Path B我必须重新初始化LegacySingleton.无法并行处理采用不同路径的请求; 对于每个不同的配置,LegacySingleton我需要启动一个单独的JVM实例.
我的问题是否有可能使用单独的类加载器来隔离这个单例?我一直在玩ClassLoaderAPI,但我无法弄明白.
我想它会看起来像这样:
public class LegacyRequestHandlerProvider extends Supplier<LegacyRequestHandler> {
private final boolean value;
public LegacyRequestHandlerProvider(boolean value) {
this.value = value;
}
@Override
public LegacyRequestHandler get() {
LegacySingleton.setup(value);
return new LegacyRequestHandler();
}
}
Run Code Online (Sandbox Code Playgroud)
...
ClassLoader loader1 = new SomeFunkyClassLoaderMagic();
Supplier<LegacyRequestHandler> supplier1 = loader1
.loadClass("com.project.LegacyRequestHandlerProvider")
.getConstructor(Boolean.TYPE)
.newInstance(true);
ClassLoader loader2 = new SomeFunkyClassLoaderMagic();
Supplier<LegacyRequestHandler> supplier2 = loader2
.loadClass("com.project.LegacyRequestHandlerProvider")
.getConstructor(Boolean.TYPE)
.newInstance(false);
LegacyRequestHandler handler1 = supplier1.get();
LegacyRequestHandler handler2 = supplier2.get();
Run Code Online (Sandbox Code Playgroud)
简单的反射是否在您希望输出发生变化的特定时间点起作用getValue?
Field f = LegacySingleton.class.getDeclaredField("value");
f.setAccessible(true);
f.set(null, true|false);
Run Code Online (Sandbox Code Playgroud)
如果没有,对于类加载器方法,您可以遵循插件架构。但正如其他人所指出的,这可能归结为将整个依赖项加载到两个不同的类加载器层次结构上。此外,您可能会遇到LinkageError问题,具体取决于依赖项在代码库中的工作方式。
受到这篇文章的启发:
LegacyRequestHandler,并且不包含在应用程序/主类路径中。有一个包装器调用程序,它将使用提供类的 jar 路径初始化类加载器LegacySingleton,例如
new ParentLastURLClassLoader(Arrays.asList(new URL[] {new URL("path/to/jar")}));
之后,您可以将单例加载到其类加载器空间中并获取副本。
//2 different classloaders
ClassLoader cl1 = new ParentLastURLClassLoader(urls);
ClassLoader cl2 = new ParentLastURLClassLoader(urls);
//LegacySingleton with value = true in Classloader space of cl1
cl1.loadClass("LegacySingleton").getMethod("setup", boolean.class).invoke(null, true);
//LegacySingleton with value = false in Classloader space of cl1
cl2.loadClass("LegacySingleton").getMethod("setup", boolean.class).invoke(null, false);
Run Code Online (Sandbox Code Playgroud)
cl1/2。请注意,您不应直接在主类中引用旧代码中的类,因为这样它们将使用 Java 原始/应用程序类加载器进行加载。
| 归档时间: |
|
| 查看次数: |
441 次 |
| 最近记录: |