メソッド置換(Spring1.2)
Springではあるbeanのあるメソッドをそのbeanの修正はおろか拡張することさえなく差し替えることができるようなので,試してみた.
今までの用語のパターンからすると,method injection(メソッド挿入)としたほうがよいかもしれない.
とにかく例によってbeans.xmlに設定を記述すると,上位からはあるbeanのあるメソッドが,別のbeanの別のメソッドに差し替えられたように見える.
以下に本頁のサンプルのbeans.xmlを示す.
idがtopBeanType1で示されるbeanと,replacedTopBeanType1で示されるbeanは,後者に要素replace-methodがある点以外は同じである.
この要素replace-methodが,メソッド置換の指定をしている.
すなわち,後者は前者のメソッド置換をしたものである.
要素replace-methodには二つの任意属性がある(※).
- name
- 置換する元メソッドの名前. あくまで名前のみ.引数は要素replace-methodの子要素で指定する.
- replacer
- 置換する先メソッドがあるbeanのid. すなわちreplacerもbeans.xmlでbeanとして設定されている必要がある.
<!ELEMENT replaced-method (
(arg-type)*
)>
要素arg-typeの内容に置換するメソッドの引数の型を記述していく.
サンプルで試してみたところ,今の段階ではどうやら引数の数は認識してくれるが,引数の型の並びは認識できないようだ.
サンプルでいうと,
<arg-type>String</arg-type> <arg-type>Integer</arg-type> <arg-type>Double</arg-type>と指定しているのに,
public Double execute(Integer paramInt, Double paramDouble, String paramString); public Double execute(String paramString, Integer paramInt, Double paramDouble);の両方のメソッドが置換される. そしてサンプルのReplaceExecuteの置換先メソッドでは後者が置換されることを想定するコードになっていないため,後者のメソッドが置換されて実行される際にClassCastExceptionとなる.
※ DTDではIMPLIEDとなっているが,意味的に省略はできないと思う.
<!ATTLIST replaced-method name CDATA #IMPLIED> <!ATTLIST replaced-method replacer CDATA #IMPLIED>実際省略すると例外となる.
サンプルで置換先メソッドが定義されているbeanである,ReplaceExecuteを以下に示す.
上のように,置換先メソッドを定義するクラスは
org.springframework.beans.factory.support.MethodReplacerを実装しなければならない. より直接的にはSpringは,メソッド置換指示があると,置換元メソッド実行時に,上記interfaceの
public Object reimplement(Object obj, Method method, Object[] args)を呼び出す. したがって,置換先メソッドは上記reimplementメソッドである. 複数のメソッドを一つのMethodReplacerで実装する場合は,どのメソッドも同じreimplementメソッド呼び出しに置換されることに注意.
サンプルドライバを以下に示す.
サンプルのドライバは,id値がtopBeanType1のbeanとreplacedTopBeanType1のbeanをBeanFactoryから取り出してメソッド呼び出しを行う.
beans.xmlにおいて前者のbeanはメソッド置換指定をしていなく,後者のbeanはメソッド置換指定をしている.
繁雑なので省略するが実行ログを確認すると,前者beanの場合は置換前メソッド,後者beanの場合は置換後メソッドが呼び出されていることがわかる(※).
※ サンプルのログ上のキーワードは,置換前メソッドがoriginal execute,置換後メソッドがreimplement.
reimplementの場合は,置換元メソッドのMethodオブジェクトも同時にログ出力している.

