- PR -

WebLogic8.1サーバ、再デプロイ時static{System.load()}がエラーになる件

1
投稿者投稿内容
kurosuke
会議室デビュー日: 2005/12/05
投稿数: 3
投稿日時: 2005-12-05 21:25
はじめまして。宜しくお願いします。

一つのWebLogicサーバインスタンスに二つのアプリケーションを
デプロイすることを想定します。

片方に影響することなしに片方のWebアプリケーションを再デプロイすることを
目標としています。

実際にやってみたところ最初は何も問題が無かったのですが
nativeメソッドを使用している
static{ System.load(ロードするパス名)}
を使用してCのライブラリを呼んでいる個所で苦戦しています。

色々調べたところWebLogicが使用しているクラスローダーにロードされており
アプリケーションの停止時にgcの対象にならない事が原因で(想像の範囲ですが)
他の暮らすローダが使用中であるとのエラーが発せられます。
(エラーメッセージ)
java.lang.UnsatisfiedLinkError: Native Library
HOGE already loaded in another classloader

ClassLoaderを新規に作成して、ネイティブライブラリを呼び出す
と言うような強引なこともやってみましたが、やはりクラスしか認識
してくれないようです。(やり方が間違っている可能性もあるのですが。。。)
ClassNotFoundExceptionであえなく撃沈。。。

使用中であればそのクラスローダーを使用してネイティブメソッドを使用
してやれば良いとも思ったのですが、現在そのやり方が分からず悩んでいます。
(クラスローダーをライブラリ名で検索→static classに参照を与えてやる??)

もしこのようなことで過去悩まれていて、解決したと言う方、
また興味のある方、アドバイスをお願いいたします。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2005-12-05 22:01
引用:

kurosukeさんの書き込み (2005-12-05 21:25) より:
一つのWebLogicサーバインスタンスに二つのアプリケーションを
デプロイすることを想定します。

片方に影響することなしに片方のWebアプリケーションを再デプロイすることを
目標としています。

実際にやってみたところ最初は何も問題が無かったのですが
nativeメソッドを使用している
static{ System.load(ロードするパス名)}
を使用してCのライブラリを呼んでいる個所で苦戦しています。


数年前のことで良く覚えていないのですが、私も同じ現象を経験しました。
特に WebLogic でなくとも、Servlet の Container ならばどれでも起きるのだったと思います。Servlet Container が、そういう仕様なので、System.loadLibrary を1回だけやるようにして、複数回やらないように、プログラマーが自分でなんらかの方法で回数を数えて管理する必要があったと記憶しています。
static initializer でやらずに、Servlet API を使って、1回だけ呼ばれるようなところで loadLibrary してみてはどうでしょうか。私は Servlet のことはあまり良く知らないので、具体的にどうやれば良いのかは分からないのですが。
あやふやなことばかり書きますが、Java World 日本語版の Servlet かなにかの特集で Q&A が100項目くらい載っている中のひとつにこの件について書いてあったような記憶があります。
kurosuke
会議室デビュー日: 2005/12/05
投稿数: 3
投稿日時: 2005-12-06 00:15
unibonさんアドバイスありがとうございます。
Webで調べたところ何人かの方がこの問題の件に関して
記述していますが、解決策まで到達しているものを見つけることが出来ませんでした。

数年前のJava worldですか、もし思い出したらまた書き込みお願いします。

1度ロードされていたら2回目はロードしない方法は試してみて
例外処理などで実現できました。
しかし、1度目のロードした情報が失われているので、
(アプリケーション側からすると再起動がかかっているので)
そのつながりを検索しなおす方法を探しています。

System.loadでロードされる場合、どのクラスローダでロードされるかは
WebLogicやらTomcatで異なるらしいのです。
bootstrapとSystemは大体デフォルトみたいですが
後は異なるらしいです。
(Java Worldのことを聞いて2005/11月号にて発見しました)

WebLogicのクラスローダの構造を少し調べてみれば何か解決策が見えるかもしれませんので、ちょっと調べてみようと思います。

アドバイスありがとうございました。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2005-12-06 00:41
JVMの仕様により、複数のクラスローダから同一のネイティブライブラリは読み込めないようになっています。
複数の Web アプリケーションや、Webアプリケーションを再デプロイするときはそれぞれ別々のクラスローダを使うことになるので UnsatisfiedLinkError が発生いたします。

回避するためには unibon さんの仰るとおり一度だけ単一のクラスローダから読み込まれるようにする必要がありいます。
アプリケーション(EAR)やWebアプリケーション(WAR)は、クラスの読み直しを行うため、再デプロイの度に新しいクラスローダが生成されます。なので ear や war にパッケージしたクラスからネイティブライブラリを読み込むのはあまり得策ではありません。

ネイティブライブラリのロードは起動クラスから行うようにしましょう。起動クラスはサーバの起動時一回だけ実行されますので。
・起動クラスと停止クラス
http://edocs.beasys.co.jp/e-docs/wls/docs81/ConsoleHelp/startup_shutdown.html
kurosuke
会議室デビュー日: 2005/12/05
投稿数: 3
投稿日時: 2005-12-06 10:11
インギさん情報ありがとうございます。

ネイティブライブラリはやはりWebLogicの固有のクラスローダーで
読み込まなければならないでしょうか?
(すみません。JVMとJAVAの言語仕様がまだ調べきれていません。)

各アプリケーション固有のネイティブライブラリと言うものがある場合、
ネイティブライブラリを改修、バージョンアップしたい場合はどうしても、
サーバ全体の再起動が必要になってしまうので困っています。

各アプリケーション固有のライブラリは各アプリケーションで
独立した設定をしたいのですが無理なのでしょうか。。。

しかし、情報ありがとうございます。
WebLogicの起動クラス、複数のアプリケーションでネイティブライブラリを
共用で使用する場合に使うのですね。
何に使うのか疑問でしたが納得しました。

アドバイスありがとうございました。

山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2005-12-06 12:47
>ネイティブライブラリを改修、バージョンアップしたい場合はどうしても、
>サーバ全体の再起動が必要になってしまうので困っています。
まぁ、そういうもんです。JNIを使う場合、ネイティブライブラリの更新には JVM の再起動が必要です。
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=18171&forum=12
最初に読み込んだクラスローダがガベージコレクションで回収されたあとならロードできるかもしれませんが、いつ回収されるか保証はされませんので。
1

スキルアップ/キャリアアップ(JOB@IT)