Java Springの逆引きメモ -12ページ目

Java Springの逆引きメモ

JavaのSpring frameworkのメモを書いていきます!
初心者の勉強ノートなので間違いがあるかもしれませんが、何かヒントになることがあれば幸いです。

'2012.03.23 追記

このブログで扱っているSpringMVCのバージョンは2.5で、情報が古くなっています。

現状、アノテーションを使用してかなり柔軟で使いやすくなっていますにひひ

この記事を削除することはしませんが、最新の情報を検索されることをお勧めします。

Spring MVC 3.xについて(日本語の記事)


ちなみに海外の記事によると、Struts1、Struts2共に今後残っていくWEBフレームワークとしては

あまり評価が高くないようです。SpringMVCが有力候補の1つのようです。

海外の記事は1つの見方であって、将来はどちらにしても分かりません。しかし、新たなWEB開発にはSpringMVC 3.0 以上が良い候補の1つかなと思いました。

2010年のフレームワーク評価一覧日本語の説明記事


-------------------------------------------------------

SpringMVCとはどんな機能かを簡単に見ていきましょう!


名前から分かるようにWEBのModel、View、Controllerを表す機能です。


ここで、念のためそれぞれの説明を書いておきます。


Model ・・・データです。ViewとControllerの間のデータのやりとりなどに使用します。

View ・・・デザインです。Javaなので、JSPを表していると思えばいいと思います。

Controller ・・・リクエストの処理や、パラメタの受け取り、ビジネスロジックへの仲立ちなどを担当します。



上記は一般に言われるものですが、正直、ちゃんと実現しているフレームワークはあまり見かけません。

どれも上記の役割分担から微妙にずれているのです。

(Strutsもそうです)


しかし、SpringのMVCはこのあたりをきれいに分担し、分離しています。

かなりいい機能だと思います。


では、実際にSpringMVCで用意しているクラスが、それぞれMVCのどれを担当するのか見てみましょう。




【SpringMVCの実際のクラス】


MVC SpringMVCの担当クラス
Model

これは自分で作ります。POJO。

View

JSPが担当します。

妥当性エラーを表示するtaglibと、画面のパラメタとModelを結びつけるtaglibとを持ちます。

ただし、SpringはModelとViewをひとつのセットとして扱う仕組みをもっています。

それは、ModelAndViewlクラスです。

名前のとおり、ModelとViewを内部に持つだけのホルダークラスですが、役割が明確になることと処理がやりやすくなる効果があります。

Controller

Controllerインターフェースとその派生クラスが用意されています。

通常はSpringで用意された派生クラスを使用します。

このクラスは、ModelAndViewクラスをreturnするように作成します。

派生クラスには、パラメタからModelを自動的に作成し、実装するメソッドに渡してくれるものもあります。




【妥当性チェック】

SpringにはValidatorが用意されています。

これはWEB用の機能ではなく、WEB以外のアプリケーションにも使用できるように設計されています。

しかし、実際の実装は、自分ですべて書式チェックを書かないといけないので面倒です。

正直言うと、インターフェースが用意されているだけです。

Controllerクラス群とうまく連携できるように放っていますが。。


このわずらわしさを解消してくれるのがSpringModulesです。

ここでは触れませんが、Strutsと同様に書式チェックを設定ファイルに書くだけで実施してくれます。

  参考:・SpringModulesの機能について



【SpringMVCの機能のメリット】

自分は、このSpringのMVCが好きですが、他の人はそれほど好きではないかもしれないですね。

MVCがきれいに分かれていて、再利用性や拡張性の高さがあること、分かりやすいこと。

そんなところが自分は好きです。

でもそれは趣味の問題かも知れないです。


そこで、SpringとStrutsの機能の比較をして、頭を整理してみます。

機能 Strutsの機能

対応するSpringの機能

Controller

Action派生クラスを継承して作成する。

Actionクラスをextendsすることになるのでフレームワークと密に関係してしまいます。

Contorollerまたはその派生クラスを継承して作成する。

ただし、Controllerはinterfaceなのでフレームワークとの独立性が高い特徴があります。

Model

FormActionクラス

FormActionを継承しないといけないためPOJOではない。再利用性は低い。

完全に画面1つについて1つのModelが密接に関係している。

自作Modelクラス。

当然、POJOにできる。再利用性が高い。

画面とModelとの結びつきは弱い。

パラメタとModelのバインド

リクエストのパラメタをFormActionクラスに設定してくれます。設定ファイルでどんなパラメタが存在するかを記述するする必要があります。

バインドできるModelは1種類だけです。

Binderクラスが担当。

Modelを指定すると、リクエストのパラメタの値をModelに設定してくれます。

Modelのsetter名と一致するパラメタ名の値が設定されます。

ですので、特に設定ファイルの記述は必要ありません。

バインドできるModelは1種類だけです。

妥当性チェック

設定ファイルに記述するだけでパラメタの書式チェックをしてくれます。

カスタマイズもできます。

Validator+SpringModulde

設定ファイルに記述するだけでパラメタの書式チェックをしてくれます。

カスタマイズもできます。

パス名の設定

設定ファイルにpathタグとして設定できます。

使用するViewも設定ファイルで設定できます。

継承機能もあり、設定の省略などもできます。

呼び出すメソッド名とパス名を*と{1}などを使用してマッピングすることもできる。

(MappingDispatchActionクラス)

jspファイル名とパス名を結びつけるような機構は存在しません。

設定ファイルにパス名と対応するControllerを設定できる。

使用するViewはControllerクラスを設定するbeanにpropertyとして定義します。

設定の継承の機能はありません。

メソッド名とパス名に*などは使用できないが、マッピングする仕組みはある。

(MultiActionControllerクラス)

jspファイル名の拡張子を変えてパス名に変換する機能もあります。

例外処理 ActionとViewの処理で例外が発生したときにキャッチでき、処理する機構がある。

Controllerの処理について例外が発生したときにキャッチでき、処理する機構がある。

ただし、Viewで発生した例外はキャッチできません。

taglib

HTMLとModelを結びつける強力な機能を用意している。

ただし使用するためには、HTMLタグの他にStruts用のタグの書式を覚える必要がある。

書式エラーを表示する機構もあります。

tilesというレイアウト支援機能があります。

HTMLとModelを結びつける機能を用意している。

Strutsとほぼ同様と思われる。もちろん使用するためには使い方を覚える必要がある。

書式エラーを表示する機構もあります。

tilesのような機能もあります。ただ微妙な面がありそうです。⇒・tilesについて

単体テスト Actionを単体テストする機構は用意されていない。 Controllerを単体テストする仕組みがある。
- - -
- - -




大雑把ですが、なんとなく比較できるでしょうか?


Strutsの特徴としては、View(tiles)に強力な機能があるのと、パス名の管理が得意、という特徴が見えます。

ただし、機能同士の依存度が高いので、再利用性は低いですし、機能の置き換えはしずらいです。

Springの特徴としては、広く浅く機能を提供していて、機能同士の依存度が低いことと、Controllerの単体テストができるのが特徴と思います。

ただし、taglibの機能には豊富さがありません。


ですので、2つを組み合わせて使いたがるのは分かる気がします。




参考:

・Controller内でApplicationContextを取得するには?

・リクエストの文字コードを設定ファイルで制御するには?

・SpringMVCを使用してWEBを作るには? (基礎編)

・Validatorでパラメタの妥当性チェックをするには?

・SpringMVCを使用してWEBを作るには? (実践編) : (パラメタとオブジェクトのバインドの方法)

・tilesについて

・SpringModulesの機能について

Spring MVC本家のHP
SpringのTiles機能(Spring本家のHP)

Tilesについてのフォーラム


ここでの記事は、StrutsとSpringJDBCをうまく連携させる工夫です。

やろうとしていることは以下のことです。


検索の入力画面があって、いくつか検索キーがあります。

それらのキーを受け取ってDaoの呼び出し、画面に結果を表示します。

プログラム的には以下のことをしないといけません。


 ①パラメタの妥当性チェック(StrtusのValidatorが行います)

 ②パラメタをActionFormから一つずつ受け取って、Daoのメソッドの引数に1つずつ設定していきます。

 ③Daoでは、パラメタを一つずつ受け取って、SQL文に一つずつセットします。


意外と面倒だと思いません?

しかも、検索キーが増えると様々な箇所に影響がありそうです。


①はStrutsが行ってくれるので、②と③についてもう少し拡張性が高く、

簡単で見通しがよい方法を見てみましょう。



【前提】

基本思想は、以下のDaoの記事にありますので、まずこちらをお読みください。


・NamedParameterJdbcTemplateをうまく使うには?



上の記事では、検索キーをクラスにすることで、型を分かりやすくし、

SpringJDBCとの連携もスムーズにする工夫を書いています。


この工夫を行っていることが前提で話を進めていきます。




【HTML画面のサンプル】


検索条件を入力してください。<br>
<html:form action="search.do" method="post">
 ID:<html:text property="id" /><br>
 名前:<html:text property="name" /><br>
 カナ:<html:text property="kana" /><br>

<html:submit value="検索" />
</html:form>



【Struts設定ファイルのform-beanタグのサンプル】

<form-bean name="schMemberKey" type="org.apache.struts.validator.DynaValidatorForm" >
<form-property name="id" type="java.lang.Integer"/>
<form-property name="name" type="java.lang.String"/>
<form-property name="kana" type="java.lang.String"/>
</form-bean>



【StrutsのActionのサンプル】

 public ActionForward execute(ActionMapping mapping, ActionForm form,
   HttpServletRequest req, HttpServletResponse res) throws Exception {
// MemberSearchKey key = new MemberSearchKey();
//コピー PropertyUtils.copyProperties(key, form); List<Member> memberList = this.memberService.findMember(key); req.setAttribute("memberList", memberList);
return mapping.findForward("search");
}

Daoは以下の記事を参照。
・NamedParameterJdbcTemplateをうまく使うには?


【説明】

使用したいDaoのメソッドは、引数がMemberSearchKeyクラスになっています。

ですので、Actionのexecuteメソッドではそのクラスを作成して値を設定すれば処理終了です!


Apache Commonsでは、PropertyUtils.copyPropertiesというメソッドが用意されています。

これは、ActionFormから値をコピーするのです。

このとき、ActionFormのプロパティ名とコピー先のプロパティ名が一致するものをコピーします。

ここでは、key にActionForm の値をコピーしています。

 PropertyUtils.copyProperties(key, form);


ですので簡単に言うと、html画面の中のパラメタをMemberSearchKeyへコピーしてくれます。

なんとこれだけで終了です。


あとはDaoでkeyを受け取って、よきに計らってくれます!



ね。簡単になりましたよね。



MemberSearchKeyを使用するやり方の補足】

上記の方法のよいところは、あとで検索キーが増えたときも変更が容易ということはもちろん。

型の安全性も保持しているところです。

Daoのメソッドは、Strutsだけでなくバッチ系の処理でも使用する可能性があります。

Strutsだけなら、上記の方法で型が分からなくても困りません。

でも、他で使用するときは、ピリオドを押したときにeclipseがsetterを補完してくれるので

分かりやすいです。

これは地味に見えますが、システムが大きくなって機能が増えるほど威力を発揮します。

開発効率が上がるのと、間違いが減るので有用な方法だと思います。





参考:

Strutsと連携するには?(理論編)

・SpringJDBCの機能について

・NamedParameterJdbcTemplateをうまく使うには?




 2010.10.23 追記

 ここの記事ですが、将来、書き直すか、削除するかもしれません。

 この記事の方法より、普通にBeanPropertySqlParameterSourceを使用するほうが

 楽そうだからです。

 勉強不足でこのクラスを知りませんでした。すみませんでした。


 BeanPropertySqlParameterSourceの使用方法は大まかに以下のとおりです。


  //検索キーのクラスの例

  public class MemberSearchKey {

   private int id;

   public int getId(){ return id; }

  }


  //Daoのメソッドの例

  public List<Member> findMember(MemberSearchKey key) {
    BeanPropertySqlParameterSource bps = new BeanPropertySqlParameterSource(key);

    //検索
    List<Member> memberList = this.namedParameterTemplate.query(
     sql, bps, new MemberRowMapper()
    );

  }


  参考に、元の記事を残しておきます↓。



---------------------------------------------------------------

前回の記事で、NamedParameterJdbcTemplateの基本的な使い方をみました。

 

 ・DBからデータを取得するには?(NamedParameterJdbcTemplateのサンプル)

 

この記事を読む前に、必ず前回の記事を読んでください。



さて、この記事ではよりうまくこのクラスを使う方法を書きます。

まず、Daoに渡すべき検索キーはMapの方が良いことを前回の記事で書きました。

しかしこれだけではまだ問題があります。


 List<Member> find(Map key);


これだと、Mapは設定できる値がObjectになるので、型が間違っているかどうかが分かりません。

例えば IDが数字とします。

しかし、 key.put("id", "0001"); と記述してもエラーにはなりません。

これを解決してみましょう。



※以下の方法はStrutsを使用する場合、もっと便利になります。

ここではStrutsを含めてお話しませんが、後日記事にしたいと思います。



【型を制限するための工夫】

これは、良くやる手です。検索キー設定用のクラスを作るのです。

「わざわざ検索キーのためだけにクラスを作るの?」と思います?

型は重要なのでクラスを作るくらいで少しでも間違いが減るなら安いものです。

しかも、Mapでは会員の検索キーを表しているのか、商品の検索キーを表しているのか、何を意味しているのかまったく分かりません。しかし、専用のクラスがあれば間違いようがありません。

可読性が高くなるおまけつきなんです。


さて、早速いってみましょう。


public class MemberSearchKey extends HashMap<String, Object> {
 //マップのキー
 final static public String ID = "id";
 final static public String NAME = "name";
 final static public String KANA = "KANA";
 
public MemberSearchKey() { // }
public int getId() { return (Integer)get(ID); }
public void setId(int id) { put(ID, id); }
public String getName() { return (String)get(NAME); }
public void setName(String name) { put(NAME, name); }
public String getKana() { return (String)get(KANA); }
public void setKana(String kana) { put(KANA, kana); }
/** @deprecated */ public Object put(String key, Object value) { //念のため使用不可にする throw new UnsupportedOperationException("使用してはいけないメソッドです。"); } }


【Daoのメソッド例】


@SuppressWarnings("unchecked") public List<Member> findMember(MemberSearchKey key) { String sql = "select * from t_member "; String where = createWhere(key);
if(!where.equals("")){ sql += " where " + where; }
//検索 List<Member> memberList = this.namedParameterTemplate.query( sql, key, new MemberRowMapper() );
return memberList; }
 /**
  * 会員情報を検索するための条件句を作成する。
  * @param params
  * @return
  */
 protected String createWhere(MemberSearchKey params)
 {
StringBuffer where = new StringBuffer();
if(!StringUtils.hasLength(params.getId())){ where.append(" and id = :"); where.append(MemberSearchKey.ID); }
if(!StringUtils.hasLength(params.getName())){ where.append(" and name like :"); where.append(MemberSearchKey.NAME); where.append(" || '%'"); } if(!StringUtils.hasLength(params.getKana())){ where.append(" and kana like :"); where.append(MemberSearchKey.KANA); where.append(" || '%'"); } return where.delete(0, 4).toString(); }

【説明】

さて、なんとなく分かるでしょうか?


まず型を制限する工夫はいたって簡単。

MemberSearchKeyをみてください。

HashMapを継承して、setterとgetterをつけています。

これで型がはっきりし、型間違いがあればコンパイラーが教えてくれます。



次に、Daoの工夫です。

findMemberをみてください。

引数はMemberSearchKeyにします。


そして、where句の部分を別のメソッドで作成しています。

そのメソッド内ではMemberSearchKeyの定数を使用して文字列を作ってます。
こうすることで、名称が変わってもeclipseのリファクタリングの機能で変更が容易になります。


 ※StringUtils.hasLength
 は、Springが提供するメソッドです。

 NULLか""のいずれかのときにtrueを返します。

 他にもStringUtilsには機能がいろいろあるので見てみてください!

 http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/util/StringUtils.html#hasText(java.lang.String )



どうでしょう。こうすることで、型の制限ができ、リファクタリングが容易になり、

可読性がよくなります。

まだ、工夫の方法はあるかもしれません。

是非、工夫してみてください!



【補足】

ちなみに、上記のcreateWhereメソッド内ではnameとkanaは前方一致にしています。
プレースホルダを使用してlikeなどを使うときは良くやる手です。


 name like ? || '%'


というように書きます。

他のプレースホルダと同様に、name like ?

というように記述したのでは、なかなかうまく行きません。

(実際に様々なケースでやってみると分かります。)


”||”は、SQLの文字列連結の記号です。つまり、?が"あいう"とすると

 name like 'あいう%'

と同じ意味です。

これはぜひ覚えておきましょうえっ



【補足2】
上記では、複数の検索キーが必要なときに検索キー専用のクラスを作る、という工夫を見ました。

おそらく大丈夫とは思いますが、念のため補足します。

上記のようなことをするのは検索キーが複数になりそうな場合で、1つしか無いような場合に無理に実施する必要は当然ありません。

例えばテーブルのprimaryキーになっているIDのようなものでレコードを検索する場合は

 Member findMember(String id);

のようにした方が使いやすいし、分かりやすいです。

また、primaryキーになっているので将来、引数を増やすこともなさそうです。

ですので、そういった場合と複数の検索キーが必要な場合とで判断して使っていきましょう!




参考:

検索画面を簡単に実現するには? (Strutsで上記工夫を使用する例)

・SpringJDBCの機能について

・SpringJDBCで作成したDaoとビジネスロジックを連携するには?

・DBからデータを取得するには?(SimpleJdbcTemplate のサンプル)

・DBからデータを取得するには?(NamedParameterJdbcTemplateのサンプル)



ここでは、SpringJDBCを使用して、DBから値を取得するサンプルを記述します。

NamedParameterJdbcTemplateクラスは、以下のような場合に良く使用します。


 ・SQL文にプレースがあり、プレースホルダに":名前"を使用したい場合


プレースホルダーは普通、"?"です。

プレースホルダに?を使用すると便利ですが、何番目かがよく分からなくなります。

こんなときに上記のように英数字で名前を使えると大変便利ですよね?


NamedParameterJdbcTemplateは、プレースするものがない場合には向きません。

その場合には、SimpleJdbcTemplate の方を使用しましょう!

さて、早速サンプルをみてみましょう。




【DaoインターフェースのJavaコード例】

import java.util.List;
import business.domain.Member;
public interface MemberDao { /** * 会員検索をする。 * @return 検索結果 */ List<Member> findMember();

}

【DaoのJavaコード例】

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.validator.GenericValidator;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;

import business.domain.Member;


public class MemberDaoImpl extends JdbcDaoSupport implements MemberDao {

  //会員情報マッピング
  protected class MemberRowMapper 
  implements ParameterizedRowMapper<Member> {
    
    public Member mapRow(ResultSet rs, int rowNum)
    throws SQLException {
        Member mem = new Member();
        mem.setId(rs.getString("id"));
        mem.setKana(rs.getString("kana"));
        mem.setKanji(rs.getString("kanji"));
      return mem;
    }
  }

  //JDBCのテンプレート
  protected NamedParameterJdbcTemplate namedParameterTemplate;
  protected SimpleJdbcTemplate simpleTemplate;
  //初期化処理
  protected void initDao()
  {
    this.namedParameterTemplate = 
                   new NamedParameterJdbcTemplate(getDataSource());
    this.simpleTemplate = new SimpleJdbcTemplate(getDataSource());
  }
  
  //  
  @SuppressWarnings("unchecked")
  public List<Member> findMember() {
    //
    String sql = "select * from t_member where id=:id";
    //パラメタの設定
    Map key = new HashMap();
    key.put("id", "i0001");

    //会員リスト
    List<Member> memberList = this.namedParameterTemplate.query(
      sql, key, new MemberRowMapper()
    ); 
    
    return memberList;
  }

}



【Springの設定】

  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.postgresql.Driver"/>
    <property name="url">
      <value>jdbc:postgresql://localhost/test?useUnicode=true&amp;characterEncoding=utf-8</value>
    </property>
    <property name="username" value="user" />
    <property name="password" value="pass" />
</bean>
  <bean id="memberDao" class="dao.MemberDaoImpl">
    <property name="dataSource" ref="dataSource" />
  </bean>


【説明】

Javaのクラスは、JdbcDaoSupport を継承してメソッドを実装していきます。

まず準備として、MemberRowMapperのようなマッピングクラスを作成します。

これは、ParameterizedRowMapperを継承して作成します。

実装するのはmapRowメソッドだけで、この中でResultSetとオブジェクトのマッピングをします。


次にするのは、実際のSQLの処理です。

SimpleJdbcTemplate と違うのはプレースするパラメタを設定する部分です。

Mapを用意してそれに値を入れます。

そして、SQL文を作ってnamedParameterTemplate.query( )を呼びます。


Springの設定ファイルでは、データソースと先ほど作成したDaoのクラスを設定するだけです。


これでDBから値を取得できます。



【その他】

SimpleJdbcTemplate と同様に、queryForIntなどの便利なメソッドもあります。


他にも便利なメソッドがあるので使っていきましょう!



【補足】

さて、NamedParameterJdbcTemplateクラスはどうでしたか?

Mapを設定するのが面倒だと思いました?


いえ、ちょっと工夫すればそうでもないんです

ここでは紙面の関係でDaoの中でMapをnewしましたが、本当はDaoを使うクラスがMapを作成すべきです

そして、Mapを引数でDaoに渡します。

そうすると柔軟性の高いDaoになります。


普通、例えば以下のように引数にSQLの検索キーを渡しがちです。


 例:AND検索で、ID、会員名、会員名カナのうち、設定されている値をキーに検索をする場合。


 List<Member> find(String id, String name, String kana);


これでも実装はできるかと思います。

しかし、上記の方法は重大な欠点があるのが分かるでしょうか

将来追加開発で、住所も検索キーにしたい場合はどうでしょう?

このメソッドを使用している箇所すべてを置換して、引数を4つにしないといけません。


これはかなり拡張性を落とします。


それよりも、以下のようにする方が断然、拡張性が高くなります。

 

 List<Member> find(Map key);


さらに、やり方を良くするための工夫は次回 に記述します。





参考:

DIの設定ファイルを書くには?

SpringJDBCの機能について

DBからデータを取得するには?(SimpleJdbcTemplate のサンプル)
NamedParameterJdbcTemplateをうまく使うには?

DIxAOPの機能の概要を見てみましょう!


まず、AOPって何でしょう?

これはSpring独自の技術というより、AspectJなどの他のフレームワークが提供している機能です。


具体的には、以下の記事を見てみてください。

AOPとは?


【Springの役割】

AOPはSpringの機能ではありません。

では、Springは何をしてくれるんでしょう?


実は、AOPの処理をAspectJなどで実現しようとすると、いろいろな準備やコードを書かないといけないんです。

上記の記事(AOPとは? )を見るとinvokeがメインなので、本当はそのコードだけを書きたいですよね?

でも、他にもいろいろやらないといけないらしいです。


Springは上のコードを書くのと、織り込む場所を設定ファイルを書くだけでいいのです。

それがDIxAOPなのです。



【SpringAOPで必要なライブラリ】
以下のライブラリをクラスパスに入れておけばとりあえず動作すると思います。

(使い方によっては不要なものもありますが。。)

 ・asm-all.jar
 ・aspectjrt.jar

 ・aspectjweaver.jar

 ・cglib-nodep.jar


 ※Googleで検索すれば簡単にダウンロードできます!



【Spring設定ファイルの記述例】

 <bean name="logging" class="aop.LoggingInterceptor" />
 <aop:config> 
   <aop:advisor pointcut="execution(* org.apache.struts.action.Action+.execute(..))"
     advice-ref="logging"  /> 
 </aop:config>

aop:という名前空間で設定します。

織り込む処理は、beanとして設定しておきます。

それをadvice-refに設定します。

織り込む場所は、pointcutで指定しますが、その記述方法が味噌です。

ここでは、executionという書き方で書いているのでそれについてみていきます。


記法は、execution(返り値の型 パッケージ名+クラス名+メソッド名(引数)) 

上記の場合は、
 execution(* org.apache.struts.action.Action+.execute(..))

返り値の型をワイルドカード指定にし、

パッケージ名はフルでそのまま記述。

クラス名は、Actionの派生クラスを指定しています。

親クラスに+をつけるとその派生クラスを示します。

メソッド名は、executeをそのまま指定しています。

引数は、..で、なんでもよいことを示す記号です。



【SpringデフォルトのAOPの注意点】

便利になったAOPですが、注意点もいくつかあります!

ただし、これはデフォルトの注意点です。

そもそもSpringはinterfaceをimplementsすることを強要するのがデフォルトです。

以下にそれに伴う注意点を記述しておきます。

(ただし、もっと自由に使う方法をその後に記述します。



Springの設定ファイルに記述したbeanに対してしか織り込みができません。

 これは、Springの設計方針なので、それほど驚くことではないかと思います。

 (自分でnewしたオブジェクトには適用されません)


・beanのメソッドの中でもpublicのメソッドのみです。


AOPは、ポイントカットで指定されたメソッドなどの呼び出し場所に織り込まれます。

 ですので、上記の注意点とあわせると以下のようになります。

 メソッドAに織り込みをしても、beanで管理していないクラスの中でA()を呼び出した場合、その位置には

 織り込まれません。


・Springファイルで設定されたbeanのメソッドを呼び出している箇所にしかポイントカットを指定できません。

・executionで、あるクラス名を含めてメソッド名を指定した場合、親クラスに記述されたメソッドは

 織り込みされません。(これは記述の注意です。親のメソッドは別途指定すればいいかと思います)


・リフレクションで呼ばれているメソッド箇所には、どうも織り込みできないっぽいです。

 (正式な文書では未確認ですが、実験した感じではそうでした)


・Aメソッドに織り込みをした場合、this.A()に対しては織り込まれないっぽいです。

 つまり、クラス内から呼ばれるケースでは織り込まれないっぽいです。

 これは、織り込みによる予期せぬ変な動きなどを防ぐ意味で、安全性のためかと思います。


・織り込みの設定は複数できるので以下のように同じ場所に違う織り込みをしたときにどういう順番になるか?

 は注意点です。

  <aop:advisor pointcut="execution(* org.apache.struts.action.Action+.execute(..))"
   advice-ref="logging" />

  <aop:advisor pointcut="execution(* org.apache.struts.action.Action+.execute(..))"
   advice-ref="stopwatch" />

 もしかしたら適用順のルールがあるかもしれませんが、自分はまだ調べ切れていません。(すみません)

 とりあえず、重ならないように設定ファイルを記述するか、重なっても大丈夫なクラスを織り込むのがいいかと。



【自由に使う方法】

上記のようにデフォルトで使用するとかなり制限がありますが、インターフェースを強要するということでは意味があるかと思います。

インターフェースを使用しなければ変更がしにくくなるからです。

しかし、場合によってはインターフェースを使用しないものにもAOPを織り込みたくなると思います。

このインターフェースを使用しなくてもよくするのが、以下の記述です。

 <aop:config proxy-target-class="true">


デフォルトではfalseです。

trueにすることで、AOPの織り込み先を、interfaceではなくclassに変更します。

これだけで、インターフェースを使用しないクラスに対してAOPが使えるようになります。

内部では、この設定によりCGLIBというライブラリを使用するようになるようです。

 ※注意点

 eclipseを使用している場合、相性が悪いのかエラーが出ます。

 「ブレークポイントを再現できません。欠落した行番号情報。」みたいなエラーです。

 原因は分かりませんが、特に問題ありませんでした。ですので無視しても良さそうな気がします。




【使いどころは?】

共通的な処理で使用するのがいいかと思います。

つまり、ルール化して開発者みんなにすぐにどこで使用しているかが分かるような箇所です。

というのは、AOPはどこにでも織り込めるため、コードを見るだけで処理を追えなくなるからです。

やたら滅多に使用するとメンテが大変になりますので注意です。


よく言われるのは、WEBのリクエストのパラメタのログをとるなどですかね。

ログなどは不具合がおきたときだけ商用でデバッグログをとったりしますが、

AOPならすぐに、どんな箇所にも織り込めます。

それに設定一つではずすこともできます!






参考:

・Springに付属のAOPサンプルのログトレースを動かすには?

・ログを出力するには?(独自のAOP処理の追加の仕方)

SpringJDBCの機能について

AOPとは?

JavaプロキシとCGLIBプロキシ