1

WebLogic アプリケーションが数週間正常に動作していた後、突然例外が発生しました。

<Oct 25, 2014 9:31:11 PM EDT> <Error> <HTTP> <BEA-101020>
    <[ServletContext@60724164[app:whatever3000 module:whatever3000.war path:
    spec-version:2.5]] Servlet failed with Exception
    java.lang.ExceptionInInitializerError

NoClassDefFoundErrorその後、アプリサーバーが再起動されるまで、アプリケーションは完全に無効になります。

完全なスタック トレースは、問題の原因がConcurrentModificationException静的初期化子にあることを示しています。

具体的には、同等/最小化されたコードは次のとおりです。

package a;
import b;

public class Whatever {
    void doIt()
    {   
        Password p = new Password();
    }   
}

package b;

public final class Password implements Serializable
{
    private static final int PARAM1 = CommonStuff.someStaticMethod();
    ... 
}

import java.util.Properties;

public class CommonStuff
{
    private static Properties prp = new Properties();

    static {
        CommonStuff.load();
    }   

    public static void load()
    {   
        prp.putAll(System.getProperties()); <---FAIL

これは例外の起源です:

java.util.ConcurrentModificationException
        at java.util.Hashtable$Enumerator.next(Hashtable.java:1017)
        at java.util.Hashtable.putAll(Hashtable.java:469)
        at b.CommonStuff.load(CommonStuff.java:55)
        at b.CommonStuff.<clinit>(CommonStuff.java:77)
        at b.Password.<clinit>(Password.java:44)
        at a.doIt(Whatever.java:99)

したがって、アプリケーションの実行中のある時点で、WebLogic はクラスをリロードすることを決定したようですが、静的ブロックが実行されると、オブジェクトが変更されているpackage bことがわかります。Properties

同時に呼び出されているのか、複数回呼び出されているのかわかりません。Propertiesオブジェクトは、アプリが初めて新しく読み込まれたときに作成された元のインスタンスであり、CommonStuffクラスのリロードが再度呼び出されようとしている可能性がありますputAll()

私がそうすれば助けになりますか:

private static Properties prp = null;

static {
    CommonStuff.prp = new Properties();
    CommonStuff.load();
}

大企業の本番アプリなので、やみくもにやってみることはできません。そのため、どこが間違っているのか、真夜中にクラスがリロードされている間にこれらの変数をプロパティ初期化する方法を理解しようとしています。

何か案は?

これは WebLogic ClassLoader の問題でしょうか?

4

1 に答える 1

3

クラス/インスタンスは、このクラスが初期化される前に一部のクラスのメンバーにアクセスできません。prpこのため、静的コンストラクターが戻る前に、誰も新しく作成されたアクセスできません。ブロックprp内で初期化子を移動しても違いはありません。static {}またprp、「古い」CommonStuffと「新しい」の「古い」prpはまったく接続されていません (「古い」と「新しい」CommonStuffは JVM の異なるクラスであるため)。prpこれにより、見た目がかなり奇妙に見える同時変更が可能になります。

理由は別のところにあると思います。スタック トレースの最初の行に注目してください。例外はEnumeratorofによってスローされHashtableます。メソッドのコードは次のputAllとおりです (JDK 8 の場合と同様に、おそらく何年も変更されていません)。

for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
    put(e.getKey(), e.getValue());

これはEnumerator、例外をスローする です。prpこれは ではなく、引数のEnumeratorです。

したがって、例外は に関連するのではなく、prpによってMap返されるものに関連していSystem.getProperties()ます。その理由は、システム プロパティ マップの反復処理がスレッド セーフではないためです。別のスレッドが同時にそれを変更しているようです。

別の方法で初期化する必要がありますprpclone()が一番簡単な方法だと思います。

于 2014-10-29T21:48:36.237 に答える