4

以下のシングルトンクラスを設計していましたが、シングルトンが壊れる可能性があることを認識しています

public class SingletonObject {
    private static SingletonObject ref;
    private SingletonObject () //private constructor
    { }

    public  static synchronized   SingletonObject getSingletonObject()
    {
        if (ref == null)
            ref = new SingletonObject();
                return ref;
        }


    public Object clone() throws CloneNotSupportedException
    {throw new CloneNotSupportedException ();
    }   
}

次のURLは、シングルトンが他の方法でクラッキングシングルトンを壊すことができる場所をすでに示唆していますが、私の質問は、このURLで示唆されているように、シングルトンはクラスローダーによって壊される可能性があり、同じクラスが2つの異なるクラスローダーによってロードされる可能性があるということです。 2 つの異なるクラス ローダーによってロードされたクラスで getInstance() メソッドを呼び出すだけで、シングルトン クラスの 2 つのインスタンスを作成します。このアプローチは、プライベート コンストラクターに違反することに頼る必要なく機能します。

ClassLoader cl1 = new URLClassLoader(new URL[]{"singleton.jar"}, null);
ClassLoader cl2 = new URLClassLoader(new URL[]{"singleton.jar"}, null);
Class<?> singClass1 = cl1.loadClass("hacking.Singleton");
Class<?> singClass2 = cl2.loadClass("hacking.Singleton");
//...
Method getInstance1 = singClass1.getDeclaredMethod("getInstance", ...);
Method getInstance2 = singClass2.getDeclaredMethod("getInstance", ...);
//...
Object singleton1 = getInstance1.invoke(null);
Object singleton2 = getInstance2.invoke(null);

また、これを回避するためにどのような措置を講じるべきか教えてください。

4

4 に答える 4

5

真のシングルトンを作成する場合は、カスタム クラスローダーの使用を避ける必要があります。すべてのシングルトンは、共通の親クラスローダーによってロードされる必要があります。

以下にリンクされている質問から問題を解決する例:

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

同様の質問:

于 2013-03-10T12:18:13.060 に答える
1

これはあなたが心配しているシナリオです:

  1. クラスローダーのクラスパスにAはありません。Singleton
  2. ClassloaderBは の子クラスローダーでAありSingleton、そのクラスパス上にあります。
  3. ClassloaderCは の子クラスローダーでAありSingleton、そのクラスパス上にあります。
  4. BCロードの両方Singleton

Singletonこれが発生すると、JLS によると ... と呼ばれる 2 つの異なる型になります。したがって、それぞれのインスタンスを作成すると、それらは異なるタイプのインスタンスになります。(間違いなく、型が同じではないため、「型の 1 つ」不変条件は破られていません。ただし、シングルトンの目的が、一度だけ保持する必要がある状態を保持することである場合、その技術的な議論は的外れです。 )

実際、そのような状況に陥った場合、 によってロードされた別のクラスはのインスタンスBを使用できなくなります。また、その逆も同様です。型が異なるためです。事実上とのクラスのセットは、それぞれシングルトン インスタンスの 1 つについてのみ「認識」します。ASingletonBC

とにかく、BCのクラスで の 1 つのインスタンスを共有する必要がある場合Singleton、それを実現する方法Singletonは、共通の親/祖先クラスローダーのクラスパスに配置することです。たとえばA、この場合。


また、これを回避するためにどのような措置を講じるべきか教えてください。

これを読み直すと、クラスローダーを使用して不変条件を誤ってまたは故意に壊すコードを他の誰かが書くのを止める方法を探しているようです。

あるとは思いません...他の人のコードを信頼できないものとして扱い、サンドボックス内で実行して、クラスローダーの作成、抽象化を破るリフレクションの使用などを防ぐ場合を除きます。

于 2013-03-10T12:43:43.623 に答える
0

このような状況を回避するには、Singleton のクラスを最上位のクラス ローダーでロードする必要があります。このような複雑なケースでは、アプリケーションの起動時、他のクラス ローダーが表示される前にこれを行う必要があります。最初にメソッドを呼び出しgetSingletonObject()て、クラスをロードし、シングルトンをインスタンス化します。子クラス ローダー (たとえば、自作) は、クラスの読み込みポリシーを破ってはなりません。最初に親クラス ローダーでクラスを検索し、次にそれ自体を読み込もうとします。ブレークすると、複数のシングルトンが出現する可能性があります。

于 2013-03-10T12:54:42.883 に答える
0

異なるローダーによってロードされたクラスには互換性がなく、両方のインスタンスを にキャストできないため、問題になるとは思いませんSingletonObject

于 2013-03-10T12:19:33.933 に答える