2010-12-26 15 views
4

私はTomcatのカスタムクラスローダーを実装しようとしています。私の最初の試みはクラスキャストの例外をもたらしました(明らかに、Tomcatは私のローダーをorg.apache.catalina.loader.WebappLoaderにキャストしようとします)。私はWebappLoaderを拡張し、catalina.jarをビルドパスに追加しました。カスタムTomcat Webapp ClassLoader

今、私は展開する準備が整いました(私は思う)。私はこのエラーを取得しています:

SEVERE: Catalina.start: LifecycleException: start: : java.lang.NoClassDefFoundError: org/apache/catalina/loader/WebappLoader

Tomcatが実行するcatalina.jarが付属していますので、私はそれがすでにTomcatのにロードされています99.9%確信しています。私は/server/lib/catalina.jarをチェックすることでこれを確認しました。これにはApache WebappLoaderが含まれています。さらに、別のcatalina.jarを手動でリンクすると、問題の混乱が予想通りに発生します。

私は混乱しています。どんなヒントも熱くなるでしょう。

ありがとうございます!興味深いことに、tomcat6(WebappLoaderの拡張; tomcat5.5での作業)と同じことが、依然としてClassCastExceptionを引き起こします。キャストを実行しているクラスが、クラスをロードしたクラスとは異なるローダーを使用してロードされているように私に聞こえます。私はどこかで別の行方不明のtomcatを設定していない限り、どうにか私はそれを制御するだろうとは思わない? tomcat6のいずれかのアイデアですか?

答えて

5

多分私は高密度ですが、WebappLoaderではなくWebappClassLoaderでなければならないと思います。しかし、インポートは大丈夫です。

+0

OMG;私はそれを信じられません。ありがとうございました!今すぐ動作します。 – Jim

1

あなたのコード&の設定の詳細を知らないと、確かめることは不可能ですが、私はカスタムクラスローダーで手を差し伸べるときに遭遇した問題を思い出させます。ブートローダーが(JVM適切/ Tomcatの/方)あなたのクラスローダは、上記のクラスパスにあなたの追加はできませんロードあなたのコード

  • をロード

    1. シナリオがこれです。

    2. あなたのコードはこれらの追加情報を参照しています。
    3. これらの追加は、ブートローダーによってロードされたコードと同じ名前空間では使用できません。
    4. ブートローダのネームスペース内のコードが実行され、カスタムネームスペースでコードを参照しようとしますが、これはブートローダのネームスペースからは見えません。したがって、その時点で、JVMはNoClassDefFoundエラーを発生させます。

    その理由は、単一方向に働くhierachyクラスローダということである:サブ名前空間(子クラスローダ)から、すなわちコードが広い親名前空間(親クラスローダ)内(可視)利用できません。このシステムにハックする良い方法はありません。

    幸いなことに、親ネームスペースで使用できるインターフェイスを定義してから、サブネームスペースにしか表示されないコードで実装することができます。次に、親の名前空間内にしか存在しないコードは、このインターフェイス名をキャスト&メソッド呼び出しの目的で使用することができるため、サブネームスペースコンポーネントには関係なくアクセスします。

    これを実行するには、カスタムクラスローダーが、親ローダーがアクセスできない(つまりクラスパスの外にある)コンポーネントをロードするだけでなく、のコードこれらのコンポーネントと直接インターフェイスし、これらのシンボル(型名/メソッドなど)を明示的に参照します。それ以外の場合、これらのコンポーネントへの参照は親の名前空間になります(デフォルトでは、ブートクラスローダーは独自のコードをすべて読み込みます)ので、元の問題に戻ります。

    これは、目的のクラスローディング委任モデルを逆転することによって実行できます。通常は、自分でクラスをロードしようとする前に、親ローダに遅延します。ただし、コードが親ローダで使用できないこれらのコンポーネントに触れないことを事前に確認する必要があります。最も簡単な方法は、おそらくクラスローダーが、クラスローダーがそれらをロードできるようにするのではなく、自分自身をロードするクラス名のセットを保持するようにコードパスを設定することです。

    カスタムクラスローダーに何らかの形で伝える方法を見つける必要があります。クラス宣言の型注釈をこれに使用できます。ここでのアイデアは、クラスローダが親によってロードされたクラスをイントロスペクションし、型名に特定のカスタム注釈が見つかった場合、注釈のメソッドを呼び出して、親ローダを許可してはいけないクラスシンボルの名前を取得する負荷。

    例:クラスMyFeatureProviderがロードされますので、MyImpl前には、あなたのクラスローダは、デフォルトの委任モデルを上書きすることができるようになりますMyFeatureProviderで注釈を事前に知ることができますされていることを

    @MyCustomAnnotation(implementation="my.custom.package.MyImpl") 
    public class MyFeatureProvider { 
        public MyFeature getFeature() { // return an instance of MyImpl here } 
    } 
    

    注意MyImplのために。残りのコードはMyImplのインスタンスとしてMyFeatureのインスタンスとしか相互作用しないため、親ローダは未定義のシンボルが見えることで決して退屈する必要はなく、ClassNoDefFoundエラーが解決されます。

  • 関連する問題