SlideShare una empresa de Scribd logo
1 de 67
Descargar para leer sin conexión
AOPとMVC
for Beginner

 2012/2/20
問題
•  インスタンス変数に宣言したのと同じ型
   のインスタンスをインジェクションして
   もらうためのアノテーションは?
•  インスタンス化され、インジェクション
   されるために、クラス宣言の前に書くア
   ノテーションは?
•  結局、DIコンテナって何のためにあるの
   か?


                         2
前回の続き
•  SpringのDIを使って、部品化はできた
   (気がする)
•  でも・・・
 ‒  ログなどの共通処理部分が部品に残っている
 ‒  例外処理も部品化を壊している
•  それに・・・
 ‒  トランザクション管理は面倒だし、難しい




                           3
Springの説明の前に・・・

AOPの基本


                  4
AOPを使ってもっと部品化する
•  AOPを使えば処理を後からクラスに追加できる
 ‒  例:トレースログを追加する

                           find()を呼ぶ	
                DaoImpl	
      ServiceImpl	
                                                 find()	
                                         Dao

                                          public class DaoImpl extends Dao{	
 >java ・・・	
                                  ・・・	
 16:00:01 *Start*   find() DaoImpl	
          public List find() {	
 16:00:02 *End*     find() DaoImpl	
              List list = select();	
 17:02:12 *Start*   find() DaoImpl	
              return list;	
 17:02:13 *End*     find() DaoImpl	
          }	
                                          }	
           実行結果	

                                                                                5
AOPをもう少し正しく
Adviceを追加できるときが
     Joinpointとなる	
      Joinpointを条件で絞り込む
                                 フィルター	

                                 Aspect

                      Pointcut              Advice

       ソースコード	

                      Pointcut              Advice

          Joinpoint


                                          追加したい処理	


                                                      6
Joinpoint
•  Adviceを追加できるとき(ポイント)
•  AOPの仕様であり、実装者は変更できない
•  Joinpointの仕様例
 ‒  メソッドの開始時、終了時
 ‒  プロパティが利用されたとき

            DaoImpl
       add()
       delete()
       find()
       update()
                      Joinpoint
                      例:メソッドの開始時や終了時	

                                     7
Pointcut
•  Joinpointに達した命令を、Adviceまで到
   達させるか否かフィルタリングするフィ
   ルター

                                 Joinpointを条件「add*」で絞り込む	


                         DaoImpl               Pointcut

                      add()
                      delete()                            Advice
ServiceImpl	
         find()
                Dao   update()
                                   Joinpoint
                                               追加したい処理	

                                                                   8
Befor Advice
•  Joinpointの前で実行される


                             メソッドの実行前に割り込む	



           method()
                      Before Advice
  Client                                          Servant
                                       return
                                      Exception




                                                            9
After Advice
•  Joinpointの後で実行される



            method()

   Client                                     Servant
                   After Advice    return
                                  Exception

                メソッドの実行後に割り込む	




                                                        10
After Returning Advice
•  Joinpointが正常終了した後に実行される


              method()
                                          return
   Client        After Returning Advice            Servant

                                    Exception
            メソッドの実行後に正常終了時
            に割り込む	




                                                             11
Around Advice
•  Joinpointの前後で実行される


           method()                   method()
  Client              Around Advice    return     Servant

                                      Exception


                 メソッドの実行前と実行後、例
                 外発生時にも割り込む	




                                                            12
Throw Advice
•  Joinpointで例外が発生した時に実行される



           method()
  Client                                   Servant
                                return
                Throw Advice   Exception


              例外発生時に割り
              込む	




                                                     13
問題
•  メソッドの開始と終了のログをとりた
   かったら?
•  メソッドが正常終了したログをとりた
   かったら?
•  メソッドが異常終了したときのログをと
   りたかったら?




                        14
AOPの仕組み例
•  Proxyベースの場合、ProxyオブジェクトはSpringが自動生成する




                                 :Bean
                                             :Advice

                         処理の
           処理の依頼	
                         依頼	
                                           Adviceの呼び出し	



 :Client                         :Proxy            :Spring
                 Interface
                                          自動生成	


                                               Bean定義
                 Pointcutの参照	
                  ファイル	

                                                             1-15
AOPの主な利用方法
•  各クラスに記述されている同一の処理を抜き出し、ひと
   まとめにして、既存のクラスに後から追加する
 ‒  ライブラリとの違い
   •  ライブラリは呼び出さないといけない
   •  AOPは勝手に追加される
•  追加すると便利な処理
 ‒  トランザクション管理
   •  トランザクション管理は難しいくプログラマに任せられない
 ‒  ログ管理
   •  メソッドの開始と終了のトレースログが正しく出力されない
     ‒  誰もフォーマットを守らない
     ‒  トレースログを追加し忘れる
 ‒  例外管理
   •  処理の途中でExceptionが握りつぶされてしまう
     ‒  Exceptionを実行時例外にする

                                    16
AOPでやらない方が良いこと
•  個別の処理(特定業務の処理、デバッ
   グ)
 ‒  プログラマが個別にAOPをいれるのは不可
  •  そこで何をやっているのかが分からなくなる


•  業務アプリのプログラマではなく、基盤
   チームとかが使う技術!?




                            17
SpringのAOP
•  定義ファイルの利用
 ‒  Spring1.x系では基本
•  アノテーションの利用
 ‒  Spring2.x系以降、アノテーションの利用が増
    えている(大規模開発や大手SI便だでは定義
    ファイルの利用が多い)




                            18
問題 書いてないけど?
•  例えば
 ‒  アノテーション
   •  メリット:定義ファイルの管理が不要
   •  デメリット:プログラマにアノテーションを意識
 ‒  とか、定義ファイルのメリットとかデメリット




                               19
アノテーションを使った
AOP


              20
アスペクトの例
•  アノテーションの利用
@Aspect
public class AspectMessage {

    @After("execution(* exMethod())")
    public void hoge() {
      // メソッド終了後に動くAdvice
      System.out.println("after called");
    }
}
                                            21
アノテーション一覧
•  アノテーションを利用したAOP
    ‒  Bean定義ファイルの記述が簡潔になる
    ‒  ソースコードに記述することで管理が煩雑

 アノテーション         	
                      説明 	
@Aspect               Adviceとなるクラスを指定するアノテーション     	
@Around               Around Adviceとなるメソッドを指定するアノテーション 	
@Before               Before Adviceとなるメソッドを指定するアノテーション	
@After                After Adviceとなるメソッドを指定するアノテーション	
@AfterReturning                                               	
                      After Returning Adviceとなるメソッドを指定するアノテーション
@AfterThrowing        After Throwing Adviceとなるメソッドを指定するアノテーション	

                                                              22
アドバイス詳細(1)
•  Before, After
   ‒  @After( Primitiveポイントカット )
      •  メソッド名は任意、メソッドのパラメータと戻り値はなしでも可能。
         メソッド内で、アスペクト対象となっているメソッド名やパラメー
         タ,戻り値などの取得をする場合は、パラメータにJoinPoint
      •  メソッド内で、アスペクト対象となっているメソッドを呼び出す必
         要はない


    @Before(“execution(* exMethod())”)
    public void hoge() {
        ・・・
    }	

                                         23
アドバイス詳細(2)
•  Around
  ‒  @Around( Primitiveポイントカット )
    •  メソッド名は任意、メソッドのパラメータには必
       ずProceedingJoinPointが必要、戻り値はアスペ
       クト対象のメソッドにあわせる
    •  メソッド内で、アスペクト対象となっているメ
       ソッドを呼び出す必要がある
      ‒  ProceedingJoinPoint#proceed()メソッド
          »  Object proceed() throws Trowable
    •  メソッド内で、アスペクト対象となっているメ
       ソッド名やメソッドのパラメータの取得は
       ProceedingJoinPointを介しておこなう

                                                24
アドバイス詳細(3)
•  Around
  ‒  戻り値はアスペクト対象にあわせる
public String getMessage() {
    return “hello!”;                アスペクト対象のメソッド
 }	

 @Around(“execution(* getMessage())”)
 public String fuga(ProceedingJoinPoint pjp)
                            throws Throwable {;
    String msg = (String)pjp.proceed();
    return msg;
 }	

                                                   25
アドバイス詳細(4)
public int getFigure() {
    return 100;            アスペクト対象のメソッド
 }	

 @Around(“execution(* getFigure())”)
 public int fuga(ProceedingJoinPoint pjp)
                              throws Throwable {;
    Integer figure= (Integer)pjp.proceed();
    return figure.intValue();
 }	

                                                    26
アドバイス詳細(5)
•  Around
  ‒  ProceedingJoinPointの使い方

  メソッド名の取得

  Signature sig = pjp.getSignature();
  System.out.println("Sig: " + sig.getName());	

          パラメータの取得(最初のパラメータ)

          Object[] os = pjp.getArgs();
          System.out.println("Args: " + os[0]);	

                                                    27
問題∼重複してたらどうなる?
@Around(“execution(* add())”)
public int hoge (ProceedingJoinPoint pjp)
                            throws Throwable {;
  Integer figure= (Integer)pjp.proceed();
  return figure.intValue();              これと同じhogehogeメソッド
}                                            が存在したら?


private int x;
public int add(int i) {
   x = x + i;                     アスペクト対象のメソッド
   return x;
 }	
                                                       28
アドバイス詳細(6)
•  AfterReturning
  ‒  @AfterReturning(value= Primitiveポイント
     カット , returnig = 戻り値の変数名 )
    •  メソッド名は任意、メソッドのパラメータはアス
       ペクト対象となっているメソッドの戻り型とアノ
       テーションのretuning属性で指定した変数名
    •  メソッド内で、アスペクト対象となっているメ
       ソッドを呼び出す必要はない




                                        29
アドバイス詳細(7)
public String exMethod() {
    return “hello!”;             アスペクト対象のメソッド

 }	



 @AfterReturning(value=“execution(* exMethod())”,
                                           returning=“ret”)
 public String hoge(String ret) {
     System.out.println(“Return: “ + ret);
 }	


                                                              30
アドバイス詳細(8)
•  AfterThrowing
  ‒  @AfterReturning(value= Primitiveポイント
     カット , throwing = 例外の変数名 )
    •  メソッド名は任意、メソッドのパラメータはアス
       ペクト対象となっているメソッドの戻り型とアノ
       テーションのthrowing属性で指定した変数名
    •  メソッド内で、アスペクト対象となっているメ
       ソッドを呼び出す必要がない




                                        31
アドバイス詳細(9)

 @AfterThrowing(value=“execution(* exMethod())”,
                              throwing=“ex”)
 public String foo(HogeException ex) {
     System.out.println(“Exception Msg: “ + ex.getMessage());
 }	




                                                            32
アドバイス詳細(10)
•  AfterThrowing
 @AfterThrowing(value=“execution(* exMethod())”, throwing=“ex”)
 public String foo(Throwable ex) {
   System.out.println(“Exception Msg: “ + ex.getMessage());
 }
 @AfterThrowing(value=“execution(* exMethod()”, throwing=“ex”)
 public String var(HogeException ex) {
   System.out.println(“Exception Msg: “ + ex.getMessage());
 }
 @AfterThrowing(value=“execution(* exMethod()”, throwing=“ex”)
 public String hoge(Exception ex) {
   System.out.println(“Exception Msg: “ + ex.getMessage());
 }


                                                                  33
問題∼どのアドバイス?
•  前ページの実装があったとき、どこかの
   プログラムがExceptionを投げてよこしま
   した
•  どのアドバイスが動くでしょう?




                         34
Primitiveポイントカット
  Primitive	
 ポイントカット        	
                      概要 	
execution	
          呼出先の「メソッド」、「コンストラクタ」を指定する。      	
within	
             呼出元の「クラス」を指定する。

                     withinをPointcutに指定すると、指定されたクラスから呼出される、メソッ
                     ド等が選択されることになる。

                     対象は、指定されたクラスで宣言されたメソッドに限定され、指定された
                     クラスの親クラスで宣言されたメソッド内は対象外となる。          	
this	
               呼出元の「クラス」を指定する。

                     thisをPointcutに指定すると、指定されたクラスから呼出される、メソッド
                     等が選択されることになる。

                     withinとは、親クラスで定義されたメソッドの呼出しも対象とする点が異な
                     る。	
target	
             呼出先の「クラス」を指定する。

                     ただし、呼出先のstaticフィールドは対象外となる。     	
args	
               呼出先「メソッド」の引数の型を指定する。       	
※Primitiveポイントカット:あらかじめ用意されているポイントカットのこと	


                                                               35
executionの基本構文
•  execution(メソッドの修飾子△メソッドの戻り値型△
   パッケージ.クラスまたはインタフェース.メソッド名
   (仮引数の型|,仮引数の型…|) △throws 例外)

•  「メソッドの修飾子(publicやprivateは省略可能)」や
   「throws△例外」は省略することが可能
•  メソッドの戻り値型、パッケージやクラス名、インタ
   フェース名にはワイルドカード(*)の利用が可能
•  仮引数に(..)を記述すると任意の個数の引数と一致さ
   せることが可能




                                  36
ポイントカットで利用できる論理演算子
論理                                               説明	
演算子	
|| または    論理和を意味する論理演算子	
or	
          例)
          execution(* *..AopExBean.exMethod()) or execution(* *..AopExBeanParent.exMethod())
           →AopExBeanのメソッドexMethodまたはAopExBeanParentのメソッドexMethodを指定	
&& また     論理積を意味する論理演算子	
は and	
          例)
          execution(* *..AopExBean.exMethod()) && execution(* *..AopExBeanParent.exMethod())
             →AopExBeanのメソッドexMethodまたはAopExBeanParentのメソッドexMethodを指定
! または     否定を意味する論理演算子。	
not	
          例)
          execution(* exMethod()) and not execution(* *..AopExBeanParent.*())
           →AopExBeanParent以外のクラス(インタフェース)のメソッドexMethodを指定	


                                                                                        37
コーディング例(1)
@Aspect
public class AspectMessage {

  @After("execution(* exMethod())")
  public void after() {
    // メソッド終了後に動作するAdvice
    System.out.println("after called");
  }

  @Before("execution(* exMethod())")
  public void before() {
    // メソッド開始時に動作するAdvice
    System.out.println("before called");
  }



                                           38
コーディング例(2)

@Around("execution(* exMethod())")
 public void around(ProceedingJoinPoint pjp) throws Throwable {
   // メソッド呼出の前後に動作するAdvice
   System.out.println("pre proceed");
   pjp.proceed();
   System.out.println("post proceed");
 }




                                                                  39
コーディング例(3)
    @AfterReturning(value="execution(* exMethod())", returning="ret")
    public void afterReturning(String ret) {
      // メソッド呼出が例外の送出なしに終了した際に動作するAdvice
      System.out.println("after returning called");
      System.out.println("return value = " + ret);
    }

    @AfterThrowing(value="execution(* exMethod())", throwing="ex")
    public void afterThrowing(Throwable ex) {
      // メソッド呼出が例外の送出なしに終了した際に動作するAdvice
      System.out.println("after throwing called");
      System.out.println("exception value = " + ex.toString());
    }
}



                                                                        40
定義ファイル
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=http://www.springframework.org/schema/beans
  xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
  xmlns:context=http://www.springframework.org/schema/context
  xmlns:aop=http://www.springframework.org/schema/aop
  xsi:schemaLocation=”
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-2.5.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
…
  <aop:aspectj-autoproxy/>
…
</beans>



                                                                          41
定義ファイルには書かないでしょ!?
AOP


                    42
それでも書きたい定義ファイル(1)

  	
 ・・・
<aop:config>
     <aop:aspect id="myAspect" ref="aspectMessage">
         <aop:pointcut id="fuga"
                expression="execution(* getMessage())"/>
         <aop:before pointcut-ref="fuga" method="foo"/>
         <aop:after pointcut-ref="fuga" method="var"/>
         <aop:around pointcut-ref="fuga" method="hoge"/>
     </aop:aspect>
</aop:config>




                                                           43
それでも書きたい定義ファイル(2)
<aop:config>
   <aop:aspect id="myAspect2" ref="aspectMessage2">
       <aop:pointcut id="fuga2"
              expression="execution(* getMessage())"/>
       <aop:after pointcut-ref="fuga2" method="hoge"/>
   </aop:aspect>
</aop:config>
・・・
<bean id="aspectMessage" class="sample.aop.AspectMsg" />
<bean id="aspectMessage2" class="sample.aop.AspectMsg2" />
・・・




                                                         44
コーディング例
public class AspectMessage {

  public void after() {
    // メソッド終了後に動作するAdvice
    System.out.println("after called");
  }

  public void before() {
    // メソッド開始時に動作するAdvice
    System.out.println("before called");
  }

・・・以下省略




                                           45
問題 消すことできる?

<aop:config>
   <aop:aspect id="myAspect2" ref="aspectMessage2">
       <aop:pointcut id="fuga2"
              expression="execution(* getMessage())"/>
                   beanを定義している2行	
       <aop:after pointcut-ref="fuga2" method="hoge"/>
   </aop:aspect>
</aop:config>
・・・
<bean id="aspectMessage2" class="sample.aop.AspectMsg2" />
<bean id="aspectMessage2" class="sample.aop.AspectMsg" />
・・・



                                                             46
今までの知識を使ってWebアプリケーションを改善する


DIとAOPのまとめ
アーキテクチャ・リファクタリング

                             47
アーキテクチャ・リファクタリング(1/5)

                                  Employee
                       Employee
          FindAction               MySql     RDB
                        Service
                                    Dao
 ブラウザ	



•  表示と永続化のフレームワーク導入済
•  インタフェース未使用(もちろんDI,AOPも)
 ‒  チーム開発がしずらい
 ‒  変更、機能拡張、テストが容易ではない
•  連続性も阻害
 ‒  Conecctionの引き回し、検査時例外の伝搬


                                                   48
アーキテクチャ・リファクタリング(2/5)
インタフェースの導入	
                        Employee                    Employee
                        Service                     Dao
                                   <<Singleton>>               <<Singleton>>
           FindAction               Employee                    Employee       MySQL
                                   ServiceImpl                  DaoMySql
ブラウザ	
                                                                          RDB
            利用	
              利用	
                                             生成	
                      生成	
                                         Factory

   •  メリット
         ‒  インタフェースを区切りとして、チーム開発がやりやすくなった
         ‒  変更、機能拡張、テストが容易になった
   •  デメリット
         ‒  Factoryを実装する必要がある
         ‒  クラスはFactoryに依存する

                                                                                  49
アーキテクチャ・リファクタリング(3/5)

DIの導入	
                         Employee                 Employee
                         Service                  Dao
                                     Employee                Employee
         FindAction                                                     MySQL
                                    ServiceImpl              DaoMySql

ブラウザ	
                                                                   RDB
                                            生成	
                 生成	

             Injection                               Injection
                                    DIコンテナ	


  •  Factoryを実装する必要がない
  •  クラスはDIコンテナに依存しない

                                                                           50
アーキテクチャ・リファクタリング(4/5)
  DIコンテナ導入後のソースコード	

                •    トランザクション管理やログ出力、例外処理が残っている
  Employee            ‒  分岐が多いため、テストの量が多くなる
 ServiceImpl          ‒  共通化できる部分が隠蔽できていない
                      ‒  例外処理とConnectionの引き渡しによる連続性の阻害がある

public class EmployeeServiceImpl"                       } catch(Exception e) {!
 implements EmployeeService{"                             conn.rollback();!
 @Autowired!                                              ・・・	
 private EmployeeDao dao;"                               } finally {!
 ・・・	
                                                    conn.close();!
 public List findAll() throws Exception {!                 ・・・	
  if(Log.flag) { System.out.println(“***Start”); }!       }!
  Connection conn = null;"                              if(Log.flag) { System.out.println(“***End”); }"
  ・・・	
                                                 return employeeList;"
   //EmployeeDao dao !                                }"
  //     = (EmployeeDao)Factory.create(KEY);!
                                                     ・・・	
  List employeeList = null;"
  try {"
     employeeList = dao.findAll(conn);"
     conn.commit();!


                                                                                                 51
アーキテクチャ・リファクタリング(5/5)
     AOP導入後のソースコード	
•    共通ライブラリを廃止してAOPを導入
•    連続性の確保
     ‒  トランザクション管理、ログ出力、例外処理はAOPで実現しているため、ソースコード上から
        はなくなっている
     ‒  Advice実装されており、なくなっている訳ではない
•    ソースコードの記述量が減り、バグの数も低下、開発者の作業も軽減
•    テストの容易性も向上

     public class EmployeeServiceImpl !    書くことがなくなりました・・・!
            implements EmploeeService {!
        @Autowired!
        private EmployeeDao dao;!

          public List findAll() {!
            return dao.findAll();!
         }!
     ・・・	




                                                              52
アーキテクチャ・リファクタリングの嘘
•  AOPで業務例外(例えば、在庫がなかった時に
   どうする)は処理できないから、そんなに奇麗
   に例外は消えない(多分…)
•  だって、AOPを使う基盤チームは業務を知らな
   い(多分…)。だから、業務例外はAOPで提供
   できない
•  それに業務例外がAOPになったら、業務プログ
   ラムが読めない!
•  そもそも、業務例外にExceptionを使うのって
   どうよ(!?)という問題でもある


                           53
かる∼く
Spring MVC


             54
Spring MVCとは
•  Spring Frameworkに含まれるWeb
   MVCフレームワーク
 ‒  初期のSpring Frameworkの段階から含まれ
    ている
 ‒  StrutsやJSFと競合
•  特徴
 ‒  DIコンテナとの親和性
 ‒  きれいな設計
   •  インタフェースを使用して部品化


                              55
Spring MVCのController

DIの導入	
                         Employee                 Employee
                         Service                  Dao
                                     Employee                Employee
         XxxController                                                  MySQL
                                    ServiceImpl              DaoMySql

ブラウザ	
                                                                   RDB
                  生成	
                      生成	
                 生成	

                                                     Injection
              Injection
                                    DIコンテナ	




                                                                           56
難しいと評判(?)のSpring MVC
•  Spring1.xのSpring MVC
  ‒  設定が難しい
  ‒  作り方がよくわからない
  ‒  日本語の情報が少ない
  ‒  そもそも知らない




                          57
簡単になったSpring MVC
•  Spring 3.xのSpring MVC
  ‒  Springの新機能を導入
    •  アノテーションにより設定がシンプルになり、わ
       かりやすくなった
    •  component-scanにより設定ファイルが最低限で
       すむようになった
  ‒  あいかわらず日本語の情報は少ない
    •  英語のマニュアルを読みましょう




                                  58
デモ
•  STS(SpringSource Tool Suite)で作成
 1.  メニューからNew->Project
 2.  SpringSource Tool Suite->Spring
     Template Projectを選択
 3.  Spring MVC Projectを選択




                                       59
動作概要

                            <<controller>>
                                                              Model	
                            HomeController	
            "serverTime"	


                                                                Date
                            home()	
            ③	
           (現在の日時)	

               Dispatcher
ブラウザ	
   ①	
     Servlet
               (ほか色々)	



                                   <<jsp>>
                            /WEB-INF/views/home.jsp	
                ⑥	




                                                                         60
HomeController
                 DIコンテナにより
                 自動で読み込まれる
                 (component-scan)	
                                        HTTPメソッドがGETで
@Controller                             「/」へアクセスした際に
public class HomeController {           実行される	

    @RequestMapping(value = "/", method = GET)
    public String home(Model model) { Viewに渡したいオブジェクトを
      Date date = new Date();         設定する	

        model.addAttribute("serverTime", date);

        return "home";
    }
                            View名をreturnする	
}

                                         ※少し手を加えシンプルにしています	
                                                          61
home.jsp

<html>
<head>
 <title>Home</title>                    Modelに設定したオブジェクトは
</head>                                 自動的にHttpServletRequestに
                                        設定されている	
<body>
<h1>Hello world! </h1>
<p>The time on the server is ${serverTime}.</p>
</body>
</html>

                                   ※少し手を加えシンプルにしています	




                                                              62
@RequestMapping色々

// 一つのメソッドに複数のURLを割り当て
@RequestMapping({"/", "/home"})
public String home() { ・・・

// 一つのURLでHTTPメソッドごとにメソッドを切り分け
@RequestMapping(value="/foo", method=GET)
public String doGetMethod() { ・・・

@RequestMapping(value="/foo", method=POST)
public String doPostMethod() { ・・・



                                             63
引数色々①
// リクエストパラメータを取得(「/person?id=10」などでアクセス)
@RequestMapping(value = "/person", method=GET)
public String showPerson1 (
     @RequestParam("id") int id, Model model) {
   Person person = findById(id);
   model.addAttribute("person", person);
   ・・・

// URLの値を取得(「/person/10」などでアクセス)
@RequestMapping(value = "/person/{id}", method=GET)
public String showPerson2(
     @PathVariable("id") int id, Model model) {
   Person person = findById(id);
   model.addAttribute("person", person);
   ・・・

                                                      64
引数色々②
// 画面からの入力をマッピング(formからデータを送信)
@RequestMapping(value = "/person", method = POST)
public String registerPerson(@ModelAttribute Person person) {
   register(person);
   ・・・



// ほかにも色々
@RequestMapping("/foo")
public String foo(
     Model model, WebRequest req, WebResponse res,
     Cookie cookie, Locale locale,
     HttpServletRequest sreq, HttpServletResponse sres) {
   ・・・

                                                                65
その他の機能
•  Session管理
   ‒  @SessionAttributes(model名)をクラスに設定すると、Modelに追加
      したオブジェクトはHttpSessionに追加される
   ‒  @ModelAttribute(model名)を引数に設定すると、Sessionのオブジェ
      クトが引数に渡される
   ‒  SessionStatus#setComplete()でHttpSession内のオブジェクトが破
      棄される
      •  ControllerごとにSession内のオブジェクトを管理可能
•  入力チェック(Validation)
   ‒  JSR-303(Bean Validation)に対応
      •  @NotNull String id;
      •  @Length(max = 30) String name;
   ‒  Validation対象の引数に@Validを設定する
•  例外処理
   ‒  例外発生時に実行するメソッドに@ExceptionHandler
      (FooException.class)

                                                      66
BON VOYAGE!




              67

Más contenido relacionado

Destacado

Средство индивидуального перемещения "СИП-С"
Средство индивидуального перемещения "СИП-С"Средство индивидуального перемещения "СИП-С"
Средство индивидуального перемещения "СИП-С"kulibin
 
司馬光 對話方塊
司馬光 對話方塊司馬光 對話方塊
司馬光 對話方塊honan4108
 
Comunicado de la oficina del coordinador residente de naciones unidas
Comunicado de la oficina del coordinador residente de naciones unidasComunicado de la oficina del coordinador residente de naciones unidas
Comunicado de la oficina del coordinador residente de naciones unidasCasa de la Mujer
 
International Group Work For Sustainable Development
International Group Work For Sustainable DevelopmentInternational Group Work For Sustainable Development
International Group Work For Sustainable DevelopmentKatherine Haxton
 
User experience for drupal
User experience for drupalUser experience for drupal
User experience for drupalAnne Stefanyk
 

Destacado (11)

Средство индивидуального перемещения "СИП-С"
Средство индивидуального перемещения "СИП-С"Средство индивидуального перемещения "СИП-С"
Средство индивидуального перемещения "СИП-С"
 
Chuong 1 new
Chuong 1 newChuong 1 new
Chuong 1 new
 
Actividades
ActividadesActividades
Actividades
 
Fall Simmer Pot Recipes
Fall Simmer Pot RecipesFall Simmer Pot Recipes
Fall Simmer Pot Recipes
 
司馬光 對話方塊
司馬光 對話方塊司馬光 對話方塊
司馬光 對話方塊
 
Comunicado de la oficina del coordinador residente de naciones unidas
Comunicado de la oficina del coordinador residente de naciones unidasComunicado de la oficina del coordinador residente de naciones unidas
Comunicado de la oficina del coordinador residente de naciones unidas
 
Evolver Architects
Evolver ArchitectsEvolver Architects
Evolver Architects
 
Soluciones de software para CTOUCH
Soluciones de software para CTOUCHSoluciones de software para CTOUCH
Soluciones de software para CTOUCH
 
International Group Work For Sustainable Development
International Group Work For Sustainable DevelopmentInternational Group Work For Sustainable Development
International Group Work For Sustainable Development
 
Squaw Lake
Squaw LakeSquaw Lake
Squaw Lake
 
User experience for drupal
User experience for drupalUser experience for drupal
User experience for drupal
 

Similar a Spring3.1 aop-mvc

試験にでるSpring
試験にでるSpring試験にでるSpring
試験にでるSpring土岐 孝平
 
Ec cube開発合宿 プラグインセミナー
Ec cube開発合宿 プラグインセミナーEc cube開発合宿 プラグインセミナー
Ec cube開発合宿 プラグインセミナーAyumu Kawaguchi
 
継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学
継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学
継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学Takuma SHIRAISHI
 
企業におけるSpring@日本springユーザー会20090624
企業におけるSpring@日本springユーザー会20090624企業におけるSpring@日本springユーザー会20090624
企業におけるSpring@日本springユーザー会20090624Yusuke Suzuki
 
作る人から作りながら運用する人になっていく
作る人から作りながら運用する人になっていく作る人から作りながら運用する人になっていく
作る人から作りながら運用する人になっていくRyo Mitoma
 
Spring Day 2016 springの現在過去未来
Spring Day 2016 springの現在過去未来Spring Day 2016 springの現在過去未来
Spring Day 2016 springの現在過去未来Yuichi Hasegawa
 
カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習
カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習
カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習Hori Tasuku
 
規模の見積もり WACATE 2016 winter
規模の見積もり WACATE 2016 winter 規模の見積もり WACATE 2016 winter
規模の見積もり WACATE 2016 winter Tomoaki Fukura
 
[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜
[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜
[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜Ryo Sasaki
 
LT13(前半)Workshipにおけるレコメンドエンジン実装
LT13(前半)Workshipにおけるレコメンドエンジン実装LT13(前半)Workshipにおけるレコメンドエンジン実装
LT13(前半)Workshipにおけるレコメンドエンジン実装GIG inc.
 
Chainerで学ぶdeep learning
Chainerで学ぶdeep learningChainerで学ぶdeep learning
Chainerで学ぶdeep learningRetrieva inc.
 
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編Fixstars Corporation
 
アジャイル開発&TFS導入
アジャイル開発&TFS導入アジャイル開発&TFS導入
アジャイル開発&TFS導入You&I
 
TotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチTotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチRWSJapan
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeKen Morishita
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniterYuya Matsushima
 
Azure Api Management 俺的マニュアル 2020年3月版
Azure Api Management 俺的マニュアル 2020年3月版Azure Api Management 俺的マニュアル 2020年3月版
Azure Api Management 俺的マニュアル 2020年3月版貴志 上坂
 
Angular2 rc.1 unit testing overview
Angular2 rc.1 unit testing overviewAngular2 rc.1 unit testing overview
Angular2 rc.1 unit testing overviewMitsuru Ogawa
 

Similar a Spring3.1 aop-mvc (20)

試験にでるSpring
試験にでるSpring試験にでるSpring
試験にでるSpring
 
Ec cube開発合宿 プラグインセミナー
Ec cube開発合宿 プラグインセミナーEc cube開発合宿 プラグインセミナー
Ec cube開発合宿 プラグインセミナー
 
継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学
継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学
継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学
 
企業におけるSpring@日本springユーザー会20090624
企業におけるSpring@日本springユーザー会20090624企業におけるSpring@日本springユーザー会20090624
企業におけるSpring@日本springユーザー会20090624
 
作る人から作りながら運用する人になっていく
作る人から作りながら運用する人になっていく作る人から作りながら運用する人になっていく
作る人から作りながら運用する人になっていく
 
Spring Day 2016 springの現在過去未来
Spring Day 2016 springの現在過去未来Spring Day 2016 springの現在過去未来
Spring Day 2016 springの現在過去未来
 
Wacate2015summer_report
Wacate2015summer_reportWacate2015summer_report
Wacate2015summer_report
 
カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習
カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習
カスタムSIで使ってみよう ~ OpenAI Gym を使った強化学習
 
規模の見積もり WACATE 2016 winter
規模の見積もり WACATE 2016 winter 規模の見積もり WACATE 2016 winter
規模の見積もり WACATE 2016 winter
 
[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜
[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜
[Okta x Jamf合同新年会] Okta Workflowsによるノーコード業務改善 〜Jamf APIを使ってMac端末情報を自動収集してみよう〜
 
LT13(前半)Workshipにおけるレコメンドエンジン実装
LT13(前半)Workshipにおけるレコメンドエンジン実装LT13(前半)Workshipにおけるレコメンドエンジン実装
LT13(前半)Workshipにおけるレコメンドエンジン実装
 
Chainerで学ぶdeep learning
Chainerで学ぶdeep learningChainerで学ぶdeep learning
Chainerで学ぶdeep learning
 
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
 
アジャイル開発&TFS導入
アジャイル開発&TFS導入アジャイル開発&TFS導入
アジャイル開発&TFS導入
 
TotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチTotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチ
 
継続的8章
継続的8章継続的8章
継続的8章
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPractice
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniter
 
Azure Api Management 俺的マニュアル 2020年3月版
Azure Api Management 俺的マニュアル 2020年3月版Azure Api Management 俺的マニュアル 2020年3月版
Azure Api Management 俺的マニュアル 2020年3月版
 
Angular2 rc.1 unit testing overview
Angular2 rc.1 unit testing overviewAngular2 rc.1 unit testing overview
Angular2 rc.1 unit testing overview
 

Más de Yuichi Hasegawa

Spring 5でSpring Testのここが変わる_公開版
Spring 5でSpring Testのここが変わる_公開版Spring 5でSpring Testのここが変わる_公開版
Spring 5でSpring Testのここが変わる_公開版Yuichi Hasegawa
 
thymeleafさいしょの一歩
thymeleafさいしょの一歩thymeleafさいしょの一歩
thymeleafさいしょの一歩Yuichi Hasegawa
 
マイクロサービス入門(Spring fest 2017)
マイクロサービス入門(Spring fest 2017)マイクロサービス入門(Spring fest 2017)
マイクロサービス入門(Spring fest 2017)Yuichi Hasegawa
 
20170525 jsug バッチは地味だが役に立つ
20170525 jsug バッチは地味だが役に立つ20170525 jsug バッチは地味だが役に立つ
20170525 jsug バッチは地味だが役に立つYuichi Hasegawa
 
Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~
Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~
Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~Yuichi Hasegawa
 
こどもの絵本 ヒトラーとナチ
 こどもの絵本 ヒトラーとナチ こどもの絵本 ヒトラーとナチ
こどもの絵本 ヒトラーとナチYuichi Hasegawa
 
Spring知っておきたい
Spring知っておきたいSpring知っておきたい
Spring知っておきたいYuichi Hasegawa
 
Spring4-DevLove発表資料
Spring4-DevLove発表資料Spring4-DevLove発表資料
Spring4-DevLove発表資料Yuichi Hasegawa
 
[Jjug]java small object programming
[Jjug]java small object programming[Jjug]java small object programming
[Jjug]java small object programmingYuichi Hasegawa
 
[豆ナイト]Java small object programming
[豆ナイト]Java small object programming[豆ナイト]Java small object programming
[豆ナイト]Java small object programmingYuichi Hasegawa
 
Jjug springセッション
Jjug springセッションJjug springセッション
Jjug springセッションYuichi Hasegawa
 

Más de Yuichi Hasegawa (15)

Spring 18年の歴史
Spring 18年の歴史Spring 18年の歴史
Spring 18年の歴史
 
Spring 5でSpring Testのここが変わる_公開版
Spring 5でSpring Testのここが変わる_公開版Spring 5でSpring Testのここが変わる_公開版
Spring 5でSpring Testのここが変わる_公開版
 
Enterprise Microservice
Enterprise MicroserviceEnterprise Microservice
Enterprise Microservice
 
thymeleafさいしょの一歩
thymeleafさいしょの一歩thymeleafさいしょの一歩
thymeleafさいしょの一歩
 
マイクロサービス入門(Spring fest 2017)
マイクロサービス入門(Spring fest 2017)マイクロサービス入門(Spring fest 2017)
マイクロサービス入門(Spring fest 2017)
 
20170525 jsug バッチは地味だが役に立つ
20170525 jsug バッチは地味だが役に立つ20170525 jsug バッチは地味だが役に立つ
20170525 jsug バッチは地味だが役に立つ
 
Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~
Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~
Application Re-Architecture Technology ~ StrutsからSpring MVCへ ~
 
こどもの絵本 ヒトラーとナチ
 こどもの絵本 ヒトラーとナチ こどもの絵本 ヒトラーとナチ
こどもの絵本 ヒトラーとナチ
 
Jsug 20160422 slides
Jsug 20160422 slidesJsug 20160422 slides
Jsug 20160422 slides
 
Spring知っておきたい
Spring知っておきたいSpring知っておきたい
Spring知っておきたい
 
Spring4-DevLove発表資料
Spring4-DevLove発表資料Spring4-DevLove発表資料
Spring4-DevLove発表資料
 
[Jjug]java small object programming
[Jjug]java small object programming[Jjug]java small object programming
[Jjug]java small object programming
 
[豆ナイト]Java small object programming
[豆ナイト]Java small object programming[豆ナイト]Java small object programming
[豆ナイト]Java small object programming
 
Jjug springセッション
Jjug springセッションJjug springセッション
Jjug springセッション
 
Spring3.1概要x di
Spring3.1概要x diSpring3.1概要x di
Spring3.1概要x di
 

Último

Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。iPride Co., Ltd.
 
プレイマットのパターン生成支援ツール
プレイマットのパターン生成支援ツールプレイマットのパターン生成支援ツール
プレイマットのパターン生成支援ツールsugiuralab
 
IoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptxIoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptxAtomu Hidaka
 
プレイマットのパターン生成支援ツールの評価
プレイマットのパターン生成支援ツールの評価プレイマットのパターン生成支援ツールの評価
プレイマットのパターン生成支援ツールの評価sugiuralab
 
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。
新人研修のまとめ       2024/04/12の勉強会で発表されたものです。新人研修のまとめ       2024/04/12の勉強会で発表されたものです。
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。iPride Co., Ltd.
 
PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000Shota Ito
 
20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directory20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directoryosamut
 

Último (8)

Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
Amazon SES を勉強してみる その12024/04/12の勉強会で発表されたものです。
 
プレイマットのパターン生成支援ツール
プレイマットのパターン生成支援ツールプレイマットのパターン生成支援ツール
プレイマットのパターン生成支援ツール
 
IoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptxIoT in the era of generative AI, Thanks IoT ALGYAN.pptx
IoT in the era of generative AI, Thanks IoT ALGYAN.pptx
 
プレイマットのパターン生成支援ツールの評価
プレイマットのパターン生成支援ツールの評価プレイマットのパターン生成支援ツールの評価
プレイマットのパターン生成支援ツールの評価
 
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。
新人研修のまとめ       2024/04/12の勉強会で発表されたものです。新人研修のまとめ       2024/04/12の勉強会で発表されたものです。
新人研修のまとめ 2024/04/12の勉強会で発表されたものです。
 
PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000PHP-Conference-Odawara-2024-04-000000000
PHP-Conference-Odawara-2024-04-000000000
 
20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directory20240412_HCCJP での Windows Server 2025 Active Directory
20240412_HCCJP での Windows Server 2025 Active Directory
 

Spring3.1 aop-mvc

  • 2. 問題 •  インスタンス変数に宣言したのと同じ型 のインスタンスをインジェクションして もらうためのアノテーションは? •  インスタンス化され、インジェクション されるために、クラス宣言の前に書くア ノテーションは? •  結局、DIコンテナって何のためにあるの か? 2
  • 3. 前回の続き •  SpringのDIを使って、部品化はできた (気がする) •  でも・・・ ‒  ログなどの共通処理部分が部品に残っている ‒  例外処理も部品化を壊している •  それに・・・ ‒  トランザクション管理は面倒だし、難しい 3
  • 5. AOPを使ってもっと部品化する •  AOPを使えば処理を後からクラスに追加できる ‒  例:トレースログを追加する find()を呼ぶ DaoImpl ServiceImpl find() Dao public class DaoImpl extends Dao{ >java ・・・ ・・・ 16:00:01 *Start* find() DaoImpl public List find() { 16:00:02 *End* find() DaoImpl List list = select(); 17:02:12 *Start* find() DaoImpl return list; 17:02:13 *End* find() DaoImpl } } 実行結果 5
  • 6. AOPをもう少し正しく Adviceを追加できるときが Joinpointとなる Joinpointを条件で絞り込む フィルター Aspect Pointcut Advice ソースコード Pointcut Advice Joinpoint 追加したい処理 6
  • 7. Joinpoint •  Adviceを追加できるとき(ポイント) •  AOPの仕様であり、実装者は変更できない •  Joinpointの仕様例 ‒  メソッドの開始時、終了時 ‒  プロパティが利用されたとき DaoImpl add() delete() find() update() Joinpoint 例:メソッドの開始時や終了時 7
  • 8. Pointcut •  Joinpointに達した命令を、Adviceまで到 達させるか否かフィルタリングするフィ ルター Joinpointを条件「add*」で絞り込む DaoImpl Pointcut add() delete() Advice ServiceImpl find() Dao update() Joinpoint 追加したい処理 8
  • 9. Befor Advice •  Joinpointの前で実行される メソッドの実行前に割り込む method() Before Advice Client Servant return Exception 9
  • 10. After Advice •  Joinpointの後で実行される method() Client Servant After Advice return Exception メソッドの実行後に割り込む 10
  • 11. After Returning Advice •  Joinpointが正常終了した後に実行される method() return Client After Returning Advice Servant Exception メソッドの実行後に正常終了時 に割り込む 11
  • 12. Around Advice •  Joinpointの前後で実行される method() method() Client Around Advice return Servant Exception メソッドの実行前と実行後、例 外発生時にも割り込む 12
  • 13. Throw Advice •  Joinpointで例外が発生した時に実行される method() Client Servant return Throw Advice Exception 例外発生時に割り 込む 13
  • 14. 問題 •  メソッドの開始と終了のログをとりた かったら? •  メソッドが正常終了したログをとりた かったら? •  メソッドが異常終了したときのログをと りたかったら? 14
  • 15. AOPの仕組み例 •  Proxyベースの場合、ProxyオブジェクトはSpringが自動生成する :Bean :Advice 処理の 処理の依頼 依頼 Adviceの呼び出し :Client :Proxy :Spring Interface 自動生成 Bean定義 Pointcutの参照 ファイル 1-15
  • 16. AOPの主な利用方法 •  各クラスに記述されている同一の処理を抜き出し、ひと まとめにして、既存のクラスに後から追加する ‒  ライブラリとの違い •  ライブラリは呼び出さないといけない •  AOPは勝手に追加される •  追加すると便利な処理 ‒  トランザクション管理 •  トランザクション管理は難しいくプログラマに任せられない ‒  ログ管理 •  メソッドの開始と終了のトレースログが正しく出力されない ‒  誰もフォーマットを守らない ‒  トレースログを追加し忘れる ‒  例外管理 •  処理の途中でExceptionが握りつぶされてしまう ‒  Exceptionを実行時例外にする 16
  • 17. AOPでやらない方が良いこと •  個別の処理(特定業務の処理、デバッ グ) ‒  プログラマが個別にAOPをいれるのは不可 •  そこで何をやっているのかが分からなくなる •  業務アプリのプログラマではなく、基盤 チームとかが使う技術!? 17
  • 18. SpringのAOP •  定義ファイルの利用 ‒  Spring1.x系では基本 •  アノテーションの利用 ‒  Spring2.x系以降、アノテーションの利用が増 えている(大規模開発や大手SI便だでは定義 ファイルの利用が多い) 18
  • 19. 問題 書いてないけど? •  例えば ‒  アノテーション •  メリット:定義ファイルの管理が不要 •  デメリット:プログラマにアノテーションを意識 ‒  とか、定義ファイルのメリットとかデメリット 19
  • 21. アスペクトの例 •  アノテーションの利用 @Aspect public class AspectMessage { @After("execution(* exMethod())") public void hoge() { // メソッド終了後に動くAdvice System.out.println("after called"); } } 21
  • 22. アノテーション一覧 •  アノテーションを利用したAOP ‒  Bean定義ファイルの記述が簡潔になる ‒  ソースコードに記述することで管理が煩雑 アノテーション 説明 @Aspect Adviceとなるクラスを指定するアノテーション @Around Around Adviceとなるメソッドを指定するアノテーション @Before Before Adviceとなるメソッドを指定するアノテーション @After After Adviceとなるメソッドを指定するアノテーション @AfterReturning After Returning Adviceとなるメソッドを指定するアノテーション @AfterThrowing After Throwing Adviceとなるメソッドを指定するアノテーション 22
  • 23. アドバイス詳細(1) •  Before, After ‒  @After( Primitiveポイントカット ) •  メソッド名は任意、メソッドのパラメータと戻り値はなしでも可能。 メソッド内で、アスペクト対象となっているメソッド名やパラメー タ,戻り値などの取得をする場合は、パラメータにJoinPoint •  メソッド内で、アスペクト対象となっているメソッドを呼び出す必 要はない @Before(“execution(* exMethod())”) public void hoge() { ・・・ } 23
  • 24. アドバイス詳細(2) •  Around ‒  @Around( Primitiveポイントカット ) •  メソッド名は任意、メソッドのパラメータには必 ずProceedingJoinPointが必要、戻り値はアスペ クト対象のメソッドにあわせる •  メソッド内で、アスペクト対象となっているメ ソッドを呼び出す必要がある ‒  ProceedingJoinPoint#proceed()メソッド »  Object proceed() throws Trowable •  メソッド内で、アスペクト対象となっているメ ソッド名やメソッドのパラメータの取得は ProceedingJoinPointを介しておこなう 24
  • 25. アドバイス詳細(3) •  Around ‒  戻り値はアスペクト対象にあわせる public String getMessage() { return “hello!”; アスペクト対象のメソッド } @Around(“execution(* getMessage())”) public String fuga(ProceedingJoinPoint pjp) throws Throwable {; String msg = (String)pjp.proceed(); return msg; } 25
  • 26. アドバイス詳細(4) public int getFigure() { return 100; アスペクト対象のメソッド } @Around(“execution(* getFigure())”) public int fuga(ProceedingJoinPoint pjp) throws Throwable {; Integer figure= (Integer)pjp.proceed(); return figure.intValue(); } 26
  • 27. アドバイス詳細(5) •  Around ‒  ProceedingJoinPointの使い方 メソッド名の取得 Signature sig = pjp.getSignature(); System.out.println("Sig: " + sig.getName()); パラメータの取得(最初のパラメータ) Object[] os = pjp.getArgs(); System.out.println("Args: " + os[0]); 27
  • 28. 問題∼重複してたらどうなる? @Around(“execution(* add())”) public int hoge (ProceedingJoinPoint pjp) throws Throwable {; Integer figure= (Integer)pjp.proceed(); return figure.intValue(); これと同じhogehogeメソッド } が存在したら? private int x; public int add(int i) { x = x + i; アスペクト対象のメソッド return x; } 28
  • 29. アドバイス詳細(6) •  AfterReturning ‒  @AfterReturning(value= Primitiveポイント カット , returnig = 戻り値の変数名 ) •  メソッド名は任意、メソッドのパラメータはアス ペクト対象となっているメソッドの戻り型とアノ テーションのretuning属性で指定した変数名 •  メソッド内で、アスペクト対象となっているメ ソッドを呼び出す必要はない 29
  • 30. アドバイス詳細(7) public String exMethod() { return “hello!”; アスペクト対象のメソッド } @AfterReturning(value=“execution(* exMethod())”, returning=“ret”) public String hoge(String ret) { System.out.println(“Return: “ + ret); } 30
  • 31. アドバイス詳細(8) •  AfterThrowing ‒  @AfterReturning(value= Primitiveポイント カット , throwing = 例外の変数名 ) •  メソッド名は任意、メソッドのパラメータはアス ペクト対象となっているメソッドの戻り型とアノ テーションのthrowing属性で指定した変数名 •  メソッド内で、アスペクト対象となっているメ ソッドを呼び出す必要がない 31
  • 32. アドバイス詳細(9) @AfterThrowing(value=“execution(* exMethod())”,                               throwing=“ex”) public String foo(HogeException ex) { System.out.println(“Exception Msg: “ + ex.getMessage()); } 32
  • 33. アドバイス詳細(10) •  AfterThrowing @AfterThrowing(value=“execution(* exMethod())”, throwing=“ex”) public String foo(Throwable ex) { System.out.println(“Exception Msg: “ + ex.getMessage()); } @AfterThrowing(value=“execution(* exMethod()”, throwing=“ex”) public String var(HogeException ex) { System.out.println(“Exception Msg: “ + ex.getMessage()); } @AfterThrowing(value=“execution(* exMethod()”, throwing=“ex”) public String hoge(Exception ex) { System.out.println(“Exception Msg: “ + ex.getMessage()); } 33
  • 34. 問題∼どのアドバイス? •  前ページの実装があったとき、どこかの プログラムがExceptionを投げてよこしま した •  どのアドバイスが動くでしょう? 34
  • 35. Primitiveポイントカット Primitive ポイントカット 概要 execution 呼出先の「メソッド」、「コンストラクタ」を指定する。 within 呼出元の「クラス」を指定する。
 withinをPointcutに指定すると、指定されたクラスから呼出される、メソッ ド等が選択されることになる。
 対象は、指定されたクラスで宣言されたメソッドに限定され、指定された クラスの親クラスで宣言されたメソッド内は対象外となる。 this 呼出元の「クラス」を指定する。
 thisをPointcutに指定すると、指定されたクラスから呼出される、メソッド 等が選択されることになる。
 withinとは、親クラスで定義されたメソッドの呼出しも対象とする点が異な る。 target 呼出先の「クラス」を指定する。
 ただし、呼出先のstaticフィールドは対象外となる。 args 呼出先「メソッド」の引数の型を指定する。 ※Primitiveポイントカット:あらかじめ用意されているポイントカットのこと 35
  • 36. executionの基本構文 •  execution(メソッドの修飾子△メソッドの戻り値型△ パッケージ.クラスまたはインタフェース.メソッド名 (仮引数の型|,仮引数の型…|) △throws 例外) •  「メソッドの修飾子(publicやprivateは省略可能)」や 「throws△例外」は省略することが可能 •  メソッドの戻り値型、パッケージやクラス名、インタ フェース名にはワイルドカード(*)の利用が可能 •  仮引数に(..)を記述すると任意の個数の引数と一致さ せることが可能 36
  • 37. ポイントカットで利用できる論理演算子 論理 説明 演算子 || または 論理和を意味する論理演算子 or 例) execution(* *..AopExBean.exMethod()) or execution(* *..AopExBeanParent.exMethod())  →AopExBeanのメソッドexMethodまたはAopExBeanParentのメソッドexMethodを指定 && また 論理積を意味する論理演算子 は and 例) execution(* *..AopExBean.exMethod()) && execution(* *..AopExBeanParent.exMethod())  →AopExBeanのメソッドexMethodまたはAopExBeanParentのメソッドexMethodを指定 ! または 否定を意味する論理演算子。 not 例) execution(* exMethod()) and not execution(* *..AopExBeanParent.*())  →AopExBeanParent以外のクラス(インタフェース)のメソッドexMethodを指定 37
  • 38. コーディング例(1) @Aspect public class AspectMessage { @After("execution(* exMethod())") public void after() { // メソッド終了後に動作するAdvice System.out.println("after called"); } @Before("execution(* exMethod())") public void before() { // メソッド開始時に動作するAdvice System.out.println("before called"); } 38
  • 39. コーディング例(2) @Around("execution(* exMethod())") public void around(ProceedingJoinPoint pjp) throws Throwable { // メソッド呼出の前後に動作するAdvice System.out.println("pre proceed"); pjp.proceed(); System.out.println("post proceed"); } 39
  • 40. コーディング例(3) @AfterReturning(value="execution(* exMethod())", returning="ret") public void afterReturning(String ret) { // メソッド呼出が例外の送出なしに終了した際に動作するAdvice System.out.println("after returning called"); System.out.println("return value = " + ret); } @AfterThrowing(value="execution(* exMethod())", throwing="ex") public void afterThrowing(Throwable ex) { // メソッド呼出が例外の送出なしに終了した際に動作するAdvice System.out.println("after throwing called"); System.out.println("exception value = " + ex.toString()); } } 40
  • 41. 定義ファイル <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=http://www.springframework.org/schema/beans xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:context=http://www.springframework.org/schema/context xmlns:aop=http://www.springframework.org/schema/aop xsi:schemaLocation=” http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> … <aop:aspectj-autoproxy/> … </beans> 41
  • 43. それでも書きたい定義ファイル(1) ・・・ <aop:config> <aop:aspect id="myAspect" ref="aspectMessage"> <aop:pointcut id="fuga" expression="execution(* getMessage())"/> <aop:before pointcut-ref="fuga" method="foo"/> <aop:after pointcut-ref="fuga" method="var"/> <aop:around pointcut-ref="fuga" method="hoge"/> </aop:aspect> </aop:config> 43
  • 44. それでも書きたい定義ファイル(2) <aop:config> <aop:aspect id="myAspect2" ref="aspectMessage2"> <aop:pointcut id="fuga2" expression="execution(* getMessage())"/> <aop:after pointcut-ref="fuga2" method="hoge"/> </aop:aspect> </aop:config> ・・・ <bean id="aspectMessage" class="sample.aop.AspectMsg" /> <bean id="aspectMessage2" class="sample.aop.AspectMsg2" /> ・・・ 44
  • 45. コーディング例 public class AspectMessage { public void after() { // メソッド終了後に動作するAdvice System.out.println("after called"); } public void before() { // メソッド開始時に動作するAdvice System.out.println("before called"); } ・・・以下省略 45
  • 46. 問題 消すことできる? <aop:config> <aop:aspect id="myAspect2" ref="aspectMessage2"> <aop:pointcut id="fuga2" expression="execution(* getMessage())"/> beanを定義している2行 <aop:after pointcut-ref="fuga2" method="hoge"/> </aop:aspect> </aop:config> ・・・ <bean id="aspectMessage2" class="sample.aop.AspectMsg2" /> <bean id="aspectMessage2" class="sample.aop.AspectMsg" /> ・・・ 46
  • 48. アーキテクチャ・リファクタリング(1/5) Employee Employee FindAction MySql RDB Service Dao ブラウザ •  表示と永続化のフレームワーク導入済 •  インタフェース未使用(もちろんDI,AOPも) ‒  チーム開発がしずらい ‒  変更、機能拡張、テストが容易ではない •  連続性も阻害 ‒  Conecctionの引き回し、検査時例外の伝搬 48
  • 49. アーキテクチャ・リファクタリング(2/5) インタフェースの導入 Employee Employee Service Dao <<Singleton>> <<Singleton>> FindAction Employee Employee MySQL ServiceImpl DaoMySql ブラウザ RDB 利用 利用 生成 生成 Factory •  メリット ‒  インタフェースを区切りとして、チーム開発がやりやすくなった ‒  変更、機能拡張、テストが容易になった •  デメリット ‒  Factoryを実装する必要がある ‒  クラスはFactoryに依存する 49
  • 50. アーキテクチャ・リファクタリング(3/5) DIの導入 Employee Employee Service Dao Employee Employee FindAction MySQL ServiceImpl DaoMySql ブラウザ RDB 生成 生成 Injection Injection DIコンテナ •  Factoryを実装する必要がない •  クラスはDIコンテナに依存しない 50
  • 51. アーキテクチャ・リファクタリング(4/5) DIコンテナ導入後のソースコード •  トランザクション管理やログ出力、例外処理が残っている Employee ‒  分岐が多いため、テストの量が多くなる ServiceImpl ‒  共通化できる部分が隠蔽できていない ‒  例外処理とConnectionの引き渡しによる連続性の阻害がある public class EmployeeServiceImpl" } catch(Exception e) {! implements EmployeeService{" conn.rollback();! @Autowired! ・・・ private EmployeeDao dao;" } finally {! ・・・ conn.close();!  public List findAll() throws Exception {! ・・・ if(Log.flag) { System.out.println(“***Start”); }! }! Connection conn = null;" if(Log.flag) { System.out.println(“***End”); }" ・・・ return employeeList;" //EmployeeDao dao ! }" // = (EmployeeDao)Factory.create(KEY);! ・・・ List employeeList = null;" try {" employeeList = dao.findAll(conn);" conn.commit();! 51
  • 52. アーキテクチャ・リファクタリング(5/5) AOP導入後のソースコード •  共通ライブラリを廃止してAOPを導入 •  連続性の確保 ‒  トランザクション管理、ログ出力、例外処理はAOPで実現しているため、ソースコード上から はなくなっている ‒  Advice実装されており、なくなっている訳ではない •  ソースコードの記述量が減り、バグの数も低下、開発者の作業も軽減 •  テストの容易性も向上 public class EmployeeServiceImpl ! 書くことがなくなりました・・・! implements EmploeeService {! @Autowired! private EmployeeDao dao;!   public List findAll() {! return dao.findAll();! }! ・・・ 52
  • 53. アーキテクチャ・リファクタリングの嘘 •  AOPで業務例外(例えば、在庫がなかった時に どうする)は処理できないから、そんなに奇麗 に例外は消えない(多分…) •  だって、AOPを使う基盤チームは業務を知らな い(多分…)。だから、業務例外はAOPで提供 できない •  それに業務例外がAOPになったら、業務プログ ラムが読めない! •  そもそも、業務例外にExceptionを使うのって どうよ(!?)という問題でもある 53
  • 55. Spring MVCとは •  Spring Frameworkに含まれるWeb MVCフレームワーク ‒  初期のSpring Frameworkの段階から含まれ ている ‒  StrutsやJSFと競合 •  特徴 ‒  DIコンテナとの親和性 ‒  きれいな設計 •  インタフェースを使用して部品化 55
  • 56. Spring MVCのController DIの導入 Employee Employee Service Dao Employee Employee XxxController MySQL ServiceImpl DaoMySql ブラウザ RDB 生成 生成 生成 Injection Injection DIコンテナ 56
  • 57. 難しいと評判(?)のSpring MVC •  Spring1.xのSpring MVC ‒  設定が難しい ‒  作り方がよくわからない ‒  日本語の情報が少ない ‒  そもそも知らない 57
  • 58. 簡単になったSpring MVC •  Spring 3.xのSpring MVC ‒  Springの新機能を導入 •  アノテーションにより設定がシンプルになり、わ かりやすくなった •  component-scanにより設定ファイルが最低限で すむようになった ‒  あいかわらず日本語の情報は少ない •  英語のマニュアルを読みましょう 58
  • 59. デモ •  STS(SpringSource Tool Suite)で作成 1.  メニューからNew->Project 2.  SpringSource Tool Suite->Spring Template Projectを選択 3.  Spring MVC Projectを選択 59
  • 60. 動作概要 <<controller>> Model HomeController "serverTime" Date home() ③ (現在の日時) Dispatcher ブラウザ ① Servlet (ほか色々) <<jsp>> /WEB-INF/views/home.jsp ⑥ 60
  • 61. HomeController DIコンテナにより 自動で読み込まれる (component-scan) HTTPメソッドがGETで @Controller 「/」へアクセスした際に public class HomeController { 実行される @RequestMapping(value = "/", method = GET) public String home(Model model) { Viewに渡したいオブジェクトを Date date = new Date(); 設定する model.addAttribute("serverTime", date); return "home"; } View名をreturnする } ※少し手を加えシンプルにしています 61
  • 62. home.jsp <html> <head> <title>Home</title> Modelに設定したオブジェクトは </head> 自動的にHttpServletRequestに 設定されている <body> <h1>Hello world! </h1> <p>The time on the server is ${serverTime}.</p> </body> </html> ※少し手を加えシンプルにしています 62
  • 63. @RequestMapping色々 // 一つのメソッドに複数のURLを割り当て @RequestMapping({"/", "/home"}) public String home() { ・・・ // 一つのURLでHTTPメソッドごとにメソッドを切り分け @RequestMapping(value="/foo", method=GET) public String doGetMethod() { ・・・ @RequestMapping(value="/foo", method=POST) public String doPostMethod() { ・・・ 63
  • 64. 引数色々① // リクエストパラメータを取得(「/person?id=10」などでアクセス) @RequestMapping(value = "/person", method=GET) public String showPerson1 ( @RequestParam("id") int id, Model model) { Person person = findById(id); model.addAttribute("person", person); ・・・ // URLの値を取得(「/person/10」などでアクセス) @RequestMapping(value = "/person/{id}", method=GET) public String showPerson2( @PathVariable("id") int id, Model model) { Person person = findById(id); model.addAttribute("person", person); ・・・ 64
  • 65. 引数色々② // 画面からの入力をマッピング(formからデータを送信) @RequestMapping(value = "/person", method = POST) public String registerPerson(@ModelAttribute Person person) { register(person); ・・・ // ほかにも色々 @RequestMapping("/foo") public String foo( Model model, WebRequest req, WebResponse res, Cookie cookie, Locale locale, HttpServletRequest sreq, HttpServletResponse sres) { ・・・ 65
  • 66. その他の機能 •  Session管理 ‒  @SessionAttributes(model名)をクラスに設定すると、Modelに追加 したオブジェクトはHttpSessionに追加される ‒  @ModelAttribute(model名)を引数に設定すると、Sessionのオブジェ クトが引数に渡される ‒  SessionStatus#setComplete()でHttpSession内のオブジェクトが破 棄される •  ControllerごとにSession内のオブジェクトを管理可能 •  入力チェック(Validation) ‒  JSR-303(Bean Validation)に対応 •  @NotNull String id; •  @Length(max = 30) String name; ‒  Validation対象の引数に@Validを設定する •  例外処理 ‒  例外発生時に実行するメソッドに@ExceptionHandler (FooException.class) 66