- - PR -
異なるバージョンのJDBCドライバの同時使用
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2004-12-28 00:47
返答が前後しちまいました。
sa2sa2さん、どうもありがとうございます。 でも残念ながらだめなんですよ。DB管理ソフトの都合で、業務DBの構成を変更するってのは。本末転倒の感もありまして。 でも、いろんなアイディアが出てくるもんですね。 このスレッドが後々、どなたかのお役に立てばうれしいですね。 | ||||
|
投稿日時: 2004-12-28 00:58
Class#forName(String name, boolean initialize, ClassLoader loader)
を使って、ドライバマネージャの初期化を行って、 そのドライバマネージャでコネクションを取得すれば よいのではと思ったのですが。。。 URLClassLoaderをドライバ(jar)分用意して、 マニフェストとURLClassLoaderをキーにするなり、 設定ファイル等の内容をキーにするなりして、 マップでURLClassLoaderを管理するのがよいかなと思います。 WEBアプリを分けるというのも、Tomcatなら各コンテキストごとに それぞれクラスローダが存在しています。 別個のアプリにしても、1つのアプリで複数のクラスローダを使用するのも 結果的には変わらないのではないでしょうか。 手元に試せる環境がないので、嘘言ってたらホントにすいません。 | ||||
|
投稿日時: 2004-12-28 14:49
かつのりさん、たびたびありがとうございます。
なんかできそうな気がしてきました。 検証は年明けになりますが、Oracle7と9.2の同時対応はどうしても実現したいので、時間がかかっても絶対やります。そして報告します。 それではまた。 | ||||
|
投稿日時: 2005-01-18 21:01
ようやく時間がとれて検証が終わりました。
結果から述べると大成功でした。 必要なステップは概ね以下の通りです。 1)クラスローダを作成 目的のJDBCドライババージョンのJARファイルのみから、クラスをロードするようなものを作ります。 実際には"org.apache.catalina.loader.WebappClassLoader"をパクりました。 パクり方は後ほど。 2)JDBCドライバのロード 1で作ったクラスローダを使って、 Class#forName(String name, boolean initialize, ClassLoader loader) を起動すればよし。 3)ドライバを取得する DriverManagerにはクセがあります。そのクセを知った上でDriverManagerを活用する方法と、いっそDriverManagerを全く使わない方法の2つがあります。 これも詳細は後ほど。 | ||||
|
投稿日時: 2005-01-18 21:20
クラスローダの作り方です。
http://www.atmarkit.co.jp/fjava/javatips/049jspservlet025.html でも説明されている階層構造に合わせ、"WebAppX"の下にそのクラスローダを置きたかったので、"WebAppX"と同じクラスを使うことにしました。(実体は "org.apache.catalina.loader.WebappClassLoader") java.net.URLClassLoaderを使うと、クラス検索を先に親クラスローダに委譲してしまうので、WebappClassLoaderを使わないと都合が悪いのです。 (WebappClassLoaderはまずローカルを検索して、なければ親に委譲) しかしWebappClassLoaderは $CATALINA_HOME/server/lib/catalina.jar の中で定義されていてWebアプリからは見えないので、以下のようにリフレクションを使いました。
ちなみにクラスローダの階層構造にこだわらなければ、単にjava.net.URLClassLoaderを使ってもよさそうなんですが、検証してません。 | ||||
|
投稿日時: 2005-01-18 21:35
クラスローダを新しく作ったら、そのそれぞれでDriverManagerをロードしてあげないといけない、と最初は考えていました。WebappClassLoaderも、J2SE標準クラスの検索だけは最初っから親クラスローダに委譲してしまうので、これは厳しい!
ところが、SunのJ2SEのDriverManagerはgetConnection()がコールされると、コール元のオブジェクトのクラスローダを判別して、それと同じクラスローダがロードしたドライバしか返さない仕様であることが判明。 つまり、クラスローダを作ったら何か適当なオブジェクトを生成して、その中で Class#forName(String name, boolean initialize, ClassLoader loader) とか、DriverManager.getConnection() してあげるとよいわけです。 しかし今回は既に存在するアプリの構造上、それが困難だったので、いっそDriverManagerに頼るのはやめることにしました。どういうことかと言うと、こういうことです。
以上のような感じでもって、同じ名前のDriverクラスの複数バージョン使い分け、をめでたく達成することができました。 色々とアイディアを提供してくれた皆さん、改めてお礼を申し上げます。 ご協力どうもありがとうございました。 |