2016-09-16 33 views
3

我有一个简单的Java单例类看起来像下面的一个:爪哇 - 辛格尔顿使用多类加载器

public class Singleton{ 
    private static Singleton instance; 

    private Singleton(){} 

    public static Singleton getInstance(){ 
     if (instance == null){ 
      instance = new Singleton(); 
     } 
     return instance; 
    } 

    public void doSomething(){ 
     ... 
    } 
} 

我的代码还包含两个班,从现在起称为A和B,这两个具有以下结构:

public class Foo{ 
    ... 
    public void bar(){ 
     ... 
     Singleton.getInstance().doSomething(); 
     ... 
    } 
    ... 
} 

在执行过程中,类A中的代码首先被执行,因此它静静地实例化单例实例。但是,稍后当B的代码被执行时,单例实例会再次被实例化,这不是我想要实现的。

经过一番调查,我们发现A类和B类使用不同的类加载器,这意味着单例类也加载两次,产生两个单例实例。

我在网上寻找解决这个问题的方法,并找到了几个(非常相似)页面,例如http://www.javaworld.com/article/2073352/core-java/simply-singleton.html?page=2http://snehaprashant.blogspot.nl/2009/01/singleton-pattern-in-java.html

但是,在尝试了几个选项之后,我仍然无法使其工作,主要是因为我不知道如何在上面列出的简单代码中应用解决方案。

所以我的问题是:有人可以提供给我一个针对上述问题的实际解决方案(线索),以便单个实例只能实例化一次,而不管正在使用哪个类加载器?

+0

您是否检查过http://stackoverflow.com/a/15157131/823393? – OldCurmudgeon

+0

@OldCurmudgeon是的,该答案基本上指向上面链接页面中所述的解决方案。但是,我不知道要采用这种方法,还需要进行哪些其他更改才能使其发挥作用。 – niellus16

+1

为什么你甚至使用不同的类加载器 - 应用程序服务器环境? – home

回答

2

我怀疑JavaWorld文章中的解决方案。 getContextClassLoader()Singleton.class.getClassLoader()每次都可以返回不同的类加载器。如果你有一个一致的类加载器,那么使用这个类的唯一方法就是通过反射。

我猜他们希望你能代替:

Singleton.getInstance().doSomething(); 

有:

try { 
    Object instance = getClass("package.Singleton").getMethod("getInstance").invoke(null); 
    instance.getClass().getMethod("doSomething").invoke(instance); 
} catch (ReflectiveOperationException e) { 
    e.printStackTrace(); 
} 

相反,我会看看为什么有多个类加载器。将所有代码放在同一个类加载器中,或者将单例放入两个类加载器的公共父类中,并使该类对于子类加载器不可用。

+0

感谢您的回答!我刚刚尝试过这个解决方案,正如你以前所想的那样:它不起作用,因为它仍然会导致多个单例实例。代码运行在CloverETL环境中,所以我会问他们为什么要使用多个类加载器,以及他们是否有解决方案。 – niellus16