【发布时间】:2018-04-20 06:53:03
【问题描述】:
免责声明:考虑到该问题,这可能不是最佳解决方案,但我很好奇如何实现此实现。
问题我正在尝试处理一些遗留代码,这些代码具有如下定义的单例:
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;
}
}
我没有能力更改此设计,并且该类在整个代码库中被大量使用。这个单例返回的值可以极大地改变代码的功能。例如:
public class LegacyRequestHandler {
public void handleRequest() {
if (LegacySingleton.getValue()) {
System.out.println("Path A");
} else {
System.out.println("Path B");
}
}
}
现在如果我希望代码采用Path A,那么我必须以特定方式初始化LegacySingleton。如果我想使用Path B,我必须重新初始化LegacySingleton。无法并行处理采用不同路径的请求;对于LegacySingleton 的每个不同配置意味着我需要启动一个单独的JVM 实例。
我的问题是否可以使用单独的类加载器来隔离这个单例?我一直在玩ClassLoader API,但我不太明白。
我想象它会看起来像这样:
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();
}
}
...
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();
【问题讨论】:
-
你必须在它们自己的类加载器中隔离/复制整个类层次结构,在你走下去之前,有很多更容易查看的可能性。但是为了让我们考虑这些可能性,您必须解释该类的作用、它的使用方式以及您的根本问题是什么(而不是您如何考虑解决它)。
-
@Kayaman 问题的根源在于遗留代码库没有提供注入配置的好方法。由于单例模式,它们与类紧密相关。如果不对代码库进行重大重写,就没有真正的方法可以为许多类提供多种配置。这可能不是最好的解决方案,但我很好奇这个解决方案需要什么(作为一个教育练习)。实际上,我最好的选择可能是将应用程序/环境容器化并运行应用程序的多个实例。
-
动态加载单例类是不够的。您必须加载层次结构,这将导致容器化之类的东西。但这可能会采取艰难的方式。不知道具体情况很难说。
-
@Kayaman 我明白了;这就说得通了。我很好奇的一个优势是无需启动多个 JVM 实例可以节省程序内存。但是如果我必须重新加载类路径中的所有内容,那么我可能不会节省太多任何东西,最终会大大增加应用程序的复杂性。那就是说;我仍然很好奇这个实现会是什么样子。我找不到任何可以使用的示例,但我可能只是不知道要搜索的正确流行语。
-
您需要向我们展示您如何决定流程显示采用路径 A 或 B,以及如何处理请求,使用什么框架?
标签: java static classloader legacy