かつのりの日記2

わんくまでは珍しいJavaを中心とした日記です

目次

Blog 利用状況

書庫

日記カテゴリ

いろいろリンク

ダイナミックプロキシの活用

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=37809&forum=12&7

@ITでnagiseさんから「敷居が高いのでは」という声があって、確かに敷居が高いなと思うので、簡単な解説を書こうかなと思います。

まず、プロキシパターンについてですが、「いつ使うか分からないし、使わないかもしれない。生成コストが高いから、ギリギリまで生成したくない。でも、できればインスタンスの有無については意識したくない」ってときに有効になります。以下のような問題を抱えているコードがあるとします。

上記コードでは、利用する側でインスタンスを取得するとき、使うか使わないか分からない状態でも関係なしにCPUが重くなります。そこでプロキシパターンを適用すると以下のようなコードになります。

まずはプロキシクラスです。(あくまでサンプルコードなので同期処理とか考慮していません)

ファクトリを引数にしてインスタンスを生成しますが、getHoge()が呼ばれるまでファクトリを経由したインスタンスの生成を行いません。しかしこのクラスはHogeを実装しているので、Hogeのインスタンスとして利用できます。利用側のコードは以下のようになります。

と、こんな感じのコードになります。ここまでが、静的なプロキシです。次に説明するのが動的なプロキシになります。

動的なプロキシとは静的なプロキシとは違い、あらかじめプロキシクラスを用意する必要がありません。APIによって動的にクラスが生成される仕組みになっています。java.lang.reflect.Proxyクラスによって提供される機能です。上記コードはProxyクラスを使う事によって以下のように置き換えすることが出来ます。

この例では前のサンプルと違い、ファクトリを汎用化しました。何かのインスタンスを生成する汎用的なファクトリです。

ダイナミックプロキシでは型を用意するなくプロキシを生成する事ができますが、その代わり実装までは作る事が出来ません。なのでメソッドの呼び出しが発生したときに、変わりに呼び出されるハンドラを用意する必要があります。そのハンドラがjava.lang.reflect.InvocationHandlerで、そのハンドラを実装しているのが、上記のInvocationHandlerImplです。

ハンドラのインスタンスと、プロキシの対象となる型オブジェクトの配列と、生成したクラスをロードさせる為のクラスローダがあれば、ダイナミックプロキシのインスタンスを生成する事が出来ます。

ダイナミックプロキシではプロキシの対象と出来る型に制約があります。それはインターフェイス型のみが対象であるということです。具象クラスや抽象クラスではプロキシの対象とする事は出来ません。ですのでプロキシパターンを動的に適用する場合は必然的にインターフェイスの定義が必要になりますので注意が必要です。

投稿日時 : 2007年4月10日 23:59

Feedback

# re: ダイナミックプロキシの活用 2007/04/11 6:47 渋木宏明(ひどり)

内容はとても良いと思うのですが、インターフェースの名称には 'I' を前置して欲しいです。
途中まで読んでいて、Hoge や HogeFactory の宣言を見直してしまいました。
VB ではガイドラインになってないんでしたっけ?>インターフェース名には 'I' を前置

# re: ダイナミックプロキシの活用 2007/04/11 8:29 かつのり

JavaではIを付けないのが一般的ですね。
例えばjava.util.Listというインターフェイスがあって、
java.util.ArrayListとjava.util.LinkedListという実装があったり、
Hogeというインターフェイスに対してHogeImplをつけるのが一般的です。
IBMあたりは先頭にIを付けることが多いかもしれません。

# re: ダイナミックプロキシの活用 2007/04/11 10:11 渋木宏明(ひどり)

ありゃ、そうでしたっけ?>Java
最後に Java で書いたのは何時の事だろう (^^; > じぶん

# re: ダイナミックプロキシの活用 2007/04/11 10:43 かつのり

確かに慣れていないと読みにくいかもしれませんね。
私の場合、逆にIで始まると一瞬迷ったりしますw

最近の流れで言うと、DIコンテナを使ったりすると、
必然的にインターフェイスと実装が1:1の関係になることが多いです。
ですので、例えばFileとFileImplという命名ルールであれば、
ソースツリー上では並びやすくてわかりやすいですね。

何はともあれ.NETとJavaでは文化が違いますね・・・

# re: ダイナミックプロキシの活用 2007/04/11 16:13 backdoor

この話題のきっかけになった質問は見てますが、Proxy鯖の話じゃないんでヌルーしますた。

nagise氏の言うとおり敷居が高くて理解できません・・・。

>「いつ使うか分からないし、使わないかもしれない。生成コストが高いから、ギリギリまで生成したくない。でも、できればインスタンスの有無については意識したくない」ってときに有効

と書かれてもJava VMの動作を理解できていない者にはほぼ理解不能ですた。
# 素人が恥ずかしいコメント付けて申し訳ないっす。

# re: ダイナミックプロキシの活用 2007/04/11 16:36 かつのり

>backdoorさん
まだちょっと難しいかもしれませんね・・・
遅延ローディング等で使うテクニックです。

1.データアクセスオブジェクトからデータを取得
2.別の処理(ここで落ちる可能性あり)
3.画面生成

という順で処理するときに、1の処理で

・データという概念を抽象化
・DAOから取得するのはデータではなく、データのプロキシ
・アプリケーションからは実データ、プロキシの意識はしない

という事をして、3の処理でデータの中身を見るときに、
初めてデータベースに接続するという方法です。

# re: ダイナミックプロキシの活用 2007/04/11 17:28 nagise

通常は静的なプロキシで十分だと思うのですよ。
プロキシの実装を動的にする必然性のあるケースというのがレアだというのが私の見解。

それこそ、デバッガ類やフレームワークなどといった「プログラムを扱うようなプログラム」を
作るときには必要となる機能だと思っています。
アスペクトのウィービングを実装する場合などには使う必然性がでるのかな?

私も勉強がてらProxyクラスのサンプルを書いたことはあるのですが、実務で使ったことはありません。
今のところ静的プロクシで事足りていますね。
この「用途不明さ」が分かりにくさの原因のひとつであると考えています。

# re: ダイナミックプロキシの活用 2007/04/11 19:41 かつのり

>nagiseさん

やっぱりどちらかというとフレームワーク向けのAPIですね。

初期のSpringFrameworkではjava.lang.reflect.ProxyでAOPをやっていたみたいですが、
最近はバイトコード操作でやることが多いですね。

# re: ダイナミックプロキシの活用 2007/04/11 20:49 中博俊

JavaのInterfaceはIをつけないですね。
コメントで付いているようにまるでCOMのInterfaceのようで、.NETのそれとは意味合いがかなり違うものになってしまっていますね。

# re: ダイナミックプロキシの活用 2007/04/12 4:51 渋木宏明(ひどり)

.NET でインターフェース名に I を前置するのは、COM からの流れなんでしょうね。
抽象クラスには何もつけないもんね。
xxxImpl って命名を見ると、ATL/WTL を思い浮かべてしまいます ;-)

# re: ダイナミックプロキシの活用 2007/04/12 9:45 シャノン

Javaって、

> public InvocationHandlerImpl(InstanceFactory factory){
> this.factory = factory;
> }

こーゆーことできるのか…。
InstanceFactory<T> じゃなくて、InstanceFactory を引数に取れるのね。

# re: ダイナミックプロキシの活用 2007/04/12 9:58 かつのり

>シャノンさん
実は警告がでますwww
型が決まらない場合ワイルドカードを指定する方法がありまして、
正確にはInstanceFactory<?>ですね。

でも警告は注釈で握りつぶすこともできます。

タイトル  
名前  
Url
コメント