新人SEの学習記録

14年度入社SEの学習記録用に始めたブログです。気づけば社会人3年目に突入。

学習記録:Spring

[学習記録] Spring

内容: 8章 Struts1とSpringの連携

Struts1の基本
  • Struts:プレゼンテーション層で利用されるフレームワーク
    • バージョンの形態として1.x系と2.x系が存在し、それぞれStruts1, Struts2と呼ばれる
    • Struts2はもともとWebWorkという名前で知られていたフレームワークで、Struts1とは本質的に異なる
    • Struts1はSpring側で、Struts2Struts側で連携の仕組みを提供
    • 本章で対象となるのはStruts1.3.10
  • Struts1は主にフロントコントローラの役割を担う
    • ユーザから全てのリクエストを受け付けて共通の処理を行うとともに、個別のコントローラに処理を振り分ける役割
    • 個別のコントローラは「アプリケーションコントローラ」と呼ばれ、ビジネスロジックの呼び出しやビューの選択を行う
    • Struts1ではActionServletクラスがフロントコントローラに、Actionクラスを継承して作成したクラスがアプリケーションコントローラにあたる
    • 以降ではActionクラスを継承して作成したクラスを単にActionと呼ぶ
  • Struts1の構成と処理フロー
  1. クライアントがWebブラウザからリクエストを行う
  2. ActionServletがリクエストを受け付け、AcionFormを生成
    • AcrionServletはStruts1が用意したクラス
    • 定義ファイル(struts-config.xml)を参照する
  3. AcrionServletはリクエストパラメータ(入力データ)をActionFormに設定
  4. AcrionServletはAcrionのメソッドexecuteを呼び出し、AcrionFormを渡す
    • どのActionを使用するか、などはStruts1が用意するActionMappingクラスを用いて判断
  5. AcrionはAcitonFormに設定された入力データを取得
  6. Actionはビジネスロジックを呼び出し、必要な処理を行った後ActionServletに処理結果を返す
  7. AcrionServletは次に表示すべきJSPを呼び出す
  8. JSPは処理結果を元にHTMLページを生成し、Webブラウザに表示する
    • JSPStrutsの用意したタグライブラリを使用可能
Struts1の課題とSpringとの連携
  • Springと連携させる場合
    • ActionからDIコンテナに配置されているサービスオブジェクトへの関連をどのように構築するかが問題
    • ActionはStrut1が生成し、そこから呼び出されるサービスオブジェクトはSpring(DIコンテナ)が生成
    • Springはこの問題の解決方法を3つ提供している
  1. ActionのProxyを儲け、ActionをDIコンテナに配置する方法
    • Actionとサービスオブジェクトの関連をDIコンテナにより構築する
    • Struts1はProxyを作成し、SpringはActionとサービスオブジェクトの両方を生成する
    • Springが提供するDelegatingActionProxyを利用する
  2. アクセスサポートクラスを設ける方法
    • DIコンテナに配置したサービスオブジェクトへのアクセスをサポートするクラス
    • Springが提供するActionSupportを利用する
    • ActionはActoinSuportの機能を利用してDIコンテナ経由でサービスオブジェクトにアクセス
  3. Actionに対しAutowireでサービスオブジェクトの関連を構築する方法
    • Springが提供するAutowiringRequestProcessorを利用する
    • Actionは直接サービスオブジェクトにアクセス
サンプルアプリケーションの概要
  1. クライアントは氏と名を入力し、ボタンを押下してサーバにリクエスト
  2. ActionServletはリクエストを受け付け、SampleFormを生成
  3. ActionServletは入力データをSampleFormに設定
  4. ActionServletはSampleActionのexecuteメソッドを呼び出し
  5. SampleActionはActionFormに設定された入力値を取得
  6. SampleActionはビジネスロジック層のSampleServiceImplクラスのオブジェクトを生成
  7. SampleActionはSampleServiceImplのメソッドを呼び出し、full nameを生成
  8. ActionServletはJSPのwelcomeを呼び出し、HTMLページを生成
DelegatingActionProxyの利用
  • DelegatingActionProxy:ActionのProxyクラス
    • struts-config.xmlにActionとして定義
    • Action定義のtype属性をDelegating...に変更するだけでOK
<action
    path="/sample"
    type="org.springframework.web.struts.DelegatingActionProxy"
    name="sampleForm"
    scope="request">
  <forward name="success" path="/WEB-INF/jsp/welcome.jsp" />
</action>
  • DelegatingActionProxyからDIコンテナに配置されたAcitonへのリクエスト委譲
    • Struts1のプラグイン機能を利用してBean定義ファイルをロードする必要
    • SpringはContextLoaderPluginを提供
    • set-propertyタグのvalue属性にBean定義ファイルを指定する
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
  <set-property property="contextConfigLocation"
    value="/WEB-INF/applicatoinContext.xml, /WEB-INF/action-servlet.xml" />
</plug-in>
  • SampleActionではサービスオブジェクトへの関連構築をDIコンテナに委任
    • @Autowiredでサービスオブジェクトをインジェクション
    • @Controllerのvalue属性はDelegatingActionProxyのAction定義で指定したpath属性と一致させる必要
    • ProxyはAction定義のpath属性と一致するvalue属性が指定されたBeanに対して、リクエスト委譲を行うため
@Controller(value = "/sample")
public class SampleAction extends Action {

    @Autowired
    private SampleService sampleService;
    
    public ActionForward execute(ActionMapping mapping, ActionForm form,
               HttpServletRequest request, HttpServletResponse response) throws Exception {
               /* 省略 */
               String fullName = sampleService.createFullName(firstName, lastName);
               /* 省略 */
    }
}
ActionSupportの利用
  • サポートクラスのActionSupportを利用した場合
    • Proxyに比べて簡単に連携可能
    • ActionSupportはActionを継承した抽象クラス
    • SampleActionはActionを直接継承するのではなく、Springが提供するActionSupportを継承させる
    • そうすることでビジネスロジック層のサービスオブジェクトにアクセスできるようになる
public class SampleAction extends ActionSupport {

    public ActionForward execute(ActionMapping mapping, ActionForm form,
               HttpServletRequest request, HttpServletResponse response) throws Exception {
               /* 省略 */
               SampleService sampleService = (SampleService)getWebApplicationContext().getBean("sampleService");
               String fullName = sampleService.createFullName(sampleForm.getFirstName(), sampleForm.getLastName());
               /* 省略 */
    }
}
  • getWebApplicationContext
  • Bean定義ファイルを読み込むクラス
    • Proxyのときと違ってStruts1のプラグイン機能を利用しなければならないという制限はない
    • web.xmlにContextLoaderListenerを指定するだけ
AutowiringRequestProcessorの利用
  • AutowiringRequestProcessor
    • ActionにAutowireでサービスオブジェクトをインジェクションするためのクラス
    • 3つの方法のうち一番新しく、最も洗練された感がある
    • web.xmlにContextLoaderListenerを指定するのはActionSupportと同様
    • あとはActionでサービスオブジェクトのインスタンス変数に@Autowiredを指定
    • struts-config.xmlのcontrollerタグでAutowiringRequestProcessorを指定すればOK
public class SampleAction extends Action {

    @Autowired
    private SampleService sampleService;

    public ActionForward execute(ActionMapping mapping, ActionForm form,
               HttpServletRequest request, HttpServletResponse response) throws Exception { 
               SampleForm sampleForm = (SampleForm) form;
               SampleService sampleService = (SampleService)getWebApplicationContext().getBean("sampleService");
               String fullName = sampleService.createFullName(sampleForm.getFirstName(), sampleForm.getLastName());
               /* 省略 */
    }
}
  • struts-config.xmlの設定は以下のとおり
<controller>
  <set-property property="processorClass"
    value="org.springframework.web.struts.AutowiringRequestProcessor" />
</controller>
  • controllerタグ
    • ActoinServletがリクエストを処理する際の挙動をカスタマイズするためのタグ
    • AutowiringRequestProcessorを指定することで、Actionの処理が呼ばれた際にDIコンテナが管理するサービスオブジェクトがActionにAutowireされる
まとめ
  • どの方法を利用するのがいいのか?
    • どの方法でもSampleActionがビジネスロジック層のインタフェースSampleServiceにのみ依存させることはできる
    • Proxyはstruts-config.xmlで指定するActionのpath属性とDIコンテナに登録するActionのBean名を一致させる必要
    • ActionSuppoerの方が明示的にBeanを取得するのでわかりやすいが、ApplicationContextを意識しないといけないので難点
    • 最後のAutowiringはApplicationContextを意識しないで済み、テストもしやすい