我最近了解到java程序可以有多个类加载器。我找到了一些StackOverflow帖子,解释了如何创建单例对象。
常见的方法是这样的:
if (instance == null) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = Singleton.class.getClassLoader();
}
Class<?> sclass = (classLoader.loadClass(Singleton.class.getCanonicalName()));
}
我不太明白这是如何解决多个类加载器的问题。如果您有多个ClassLoader,则当每个实例加载该类时,该实例将为null。这不对吗?如果我能得到一个关于它是如何工作的简短解释,我会觉得很有帮助。
此外,我们在什么时候能够检索实际的Singleton实例?我可以执行instance = (Singleton) sclass.newInstance();
之类的操作,但这会为每个ClassLoader
创建一个新实例。
答案 0 :(得分:0)
如何解决多个类加载器的问题。
我不知道你指的是哪个问题,但它没有解决任何问题。
当每个实例都尝试加载该类时,该实例将为null。
实例不会为空。
我们能够检索实际的Singleton实例吗?
当线程具有所需的ClassLoader时,您可以使用其中任何一个获取SIngleton实例。
Singleton s = Singleton.INSTANCE;
或
Singleton s = Singleton.getInstance();
取决于您正常访问Singleton的方式。如果你需要另一个ClassLoader中的singelton,你必须做同样的事情,除非通过反射。
答案 1 :(得分:0)
有很多例子,但它们似乎是从JavaWorld上的文章中复制而来。
它没有摆脱多个类加载器的问题。您仍然可以拥有多个实例。
它尝试通过线程上下文类加载器加载类。问题是你不能依赖于任何特定的类加载器,或者每个线程或者调用它的地方都是相同的。如果这不可用,那么它会尝试Singleton.class.getClassLoader()
这是将要使用的类加载器,并且不保证每次都是相同的。
如果上下文类加载器始终相同,那么每次都会获得相同的实例,但是您需要通过反射访问此实例。您无法将其转换为正确的类型,或者您获得ClassCastException
,因为加载该类的类加载器与当前类不匹配。
以下示例演示getClass
方法的用法,使用ByteBuddy库创建类加载器:
public class Main {
public static void main(String[] args) throws Exception {
run();
run();
}
public static void run() throws Exception {
ClassLoader parent = Main.class.getClassLoader();
byte[] runnerBytes = Files.readAllBytes(new File("/path/to/bin/Runner.class").toPath());
byte[] singletonBytes = Files.readAllBytes(new File("/path/to/bin/Singleton.class").toPath());
Map<String, byte[]> classes = new HashMap<>();
classes.put("Runner", runnerBytes);
classes.put("Singleton", singletonBytes);
ByteArrayClassLoader classLoader = new ByteArrayClassLoader.ChildFirst(
parent,
classes,
null,
ByteArrayClassLoader.PersistenceHandler.MANIFEST,
PackageDefinitionStrategy.NoOp.INSTANCE
);
Class<?> clazz = classLoader.loadClass("Runner");
Thread.currentThread().setContextClassLoader(classLoader);
Object instance = clazz.newInstance();
clazz.getMethod("run").invoke(instance);
}
}
public class Runner {
public void run() {
try {
Object instance = getClass("Singleton").getMethod("getInstance").invoke(null);
Object result = instance.getClass().getMethod("getValue").invoke(instance);
System.out.println("RESULT: " + result);
} catch(ReflectiveOperationException e) {
e.printStackTrace();
}
}
private static Class<?> getClass(String className) throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader == null) {
classLoader = Singleton.class.getClassLoader();
}
return (classLoader.loadClass(className));
}
}
public class Singleton {
private static final Singleton instance = new Singleton();
private double value = Math.random();
public static Singleton getInstance() {
return instance;
}
public double getValue() {
return value;
}
}
结果:
RESULT: 0.8998675708591397
RESULT: 0.7230302140857906
所以这不会创建相同的实例。