简体   繁体   English

具有多个不同类加载器的单例类

[英]Singleton class with several different classloaders

Eg I have class Singleton with static field instance :例如,我有带有静态字段instance Singleton类:

public class Singleton {

    private static Singleton instance;

    // other code, construct, getters, no matter    
}

I can load this class twice with two different classloaders.我可以用两个不同的类加载器加载这个类两次。 How could I avoid it?我怎么能避免呢? It is unsafe and dangerous.这是不安全和危险的。

Also, if I set instance to null, would it set to null for both classes?另外,如果我将 instance 设置为 null,它是否会为两个类都设置为 null?

Singleton singleton = Singleton.getInstance();
singleton = null;

If you want a true Singleton across classloaders, then you need a common parent to load the class in question, or you need to specify the classloader yourself.如果你想要一个真正的跨类加载器的Singleton ,那么你需要一个共同的父类来加载有问题的类,或者你需要自己指定类加载器。

Update: From the comment from @Pshemo below a fair bit of the content in the blog below might come directly from a JavaWorld Article .更新:下面来自@Pshemo 的评论,下面博客中的相当一部分内容可能直接来自JavaWorld 文章 I've left the blog entry in as it may still help someone, but its worth knowing where the content originally came from.我已经留下了博客条目,因为它可能仍然对某人有帮助,但值得知道内容最初来自哪里。

Original: There is a blog entry that gives you a way to do this" (although I havent tried it!), and it looks fairly reasonable原文:有一篇博文让你有办法做到这一点”(虽然我没试过!),看起来还算合理

As requested below here a code snippet from my link above - I do suggest you visit the blog though for the full context:根据下面的要求,我上面链接中的代码片段 - 我建议您访问博客以获取完整的上下文:

private static Class getClass(String classname) throws ClassNotFoundException {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader == null) 
        classLoader = Singleton.class.getClassLoader();
      return (classLoader.loadClass(classname));
}

This is a hack misusing the fact that Properties extends Map , an old unfortunate design decision.这是一个滥用Properties扩展Map的事实,这是一个旧的不幸的设计决定。

public final class JvmWideSingleton
{
    private static final JvmWideSingleton INSTANCE;

    static {
        // There should be just one system class loader object in the whole JVM.
        synchronized(ClassLoader.getSystemClassLoader()) {
            Properties sysProps = System.getProperties();
            // The key is a String, because the .class object would be different across classloaders.
            JvmWideSingleton singleton = (JvmWideSingleton) sysProps.get(JvmWideSingleton.class.getName());

            // Some other class loader loaded JvmWideSingleton earlier.
            if (singleton != null) {
                INSTANCE = singleton;
            }
            else {
                // Otherwise this classloader is the first one, let's create a singleton.
                // Make sure not to do any locking within this.
                INSTANCE = new JvmWideSingleton();
                System.getProperties().put(JvmWideSingleton.class.getName(), INSTANCE);
            }
        }
    }

    public static JvmWideSingleton getSingleton() {
        return INSTANCE;
    }
}

This could be made parametrized, but then the initialization would be lazy and go to getSingleton() .这可以进行参数化,但是初始化会很懒惰并转到getSingleton()

Properties is Hashtable -based, so it is thread safe (as per the documentation). Properties是基于Hashtable的,因此它是线程安全的(根据文档)。 So one could use props.computeIfAbsent() .所以可以使用props.computeIfAbsent() But I like it this way more.但我更喜欢这种方式。

Also read here: Scope of the Java System Properties另请阅读此处: Java 系统属性的范围

I just wrote it and there is a chance there's something I overlooked that would prevent this from working.我刚刚写了它,并且有可能我忽略了一些会阻止它工作的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM