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

Java Springの逆引きメモ

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


AOPについて、軽く見ていきましょう!


AOPは、ソースを書き直すことなく、メソッドの前後に新しい処理を織り込む機能です。

これはJavaの実行ファイルを読み込むときに、指定の位置のバイナリを書き換えるのです。

まあ、実際に実装のイメージを見てみたほうが早いと思うので、いってみましょうかお



【イメージ】

例えばメソッドaaaがあったとすると、以下のような感じです。


 int aaa(String msg){

  ・・・

 }



織り込む処理のイメージ:

 public Object invoke(MethodInvocation invocation) throws Throwable {
  //メソッド名を取得("aaa"が渡ってくる)
  String name = invocation.getMethod().getName();

//メソッド実行 int ret = (Integer)invocation.proceed();

return ret; }



【説明】
なんとなく分かるでしょうか?

AOPの機能がAメソッドを乗っ取って、Aメソッドが呼び出されるところで代わりに

invokeというメソッドが呼び出されます。

invokeは、proceed()というメソッドを使用して実際の処理(メソッドaaa())を実行します。

この前後でtry~catchしたり、ログの処理を書いたりします。


MethodInvocation について

 このクラスは、メソッド自体を表すクラスで、この中にメソッド名やメソッドの引数などを保持しています。

 ですので、メソッド名が"get"から始まっているときに何かを処理する、などいろいろ幅広くできます!


あくまで、上記はひとつの例です。

こんな感じで、メソッドやクラスの織り込みを行います。






参考:

・DIxAOPの機能について
・Springのトランザクション機能について
・トランザクションのコードを書かないようにするには?(宣言的トランザクション)


tomcatで設定できるfilterとは何でしょう?


フィルターとは、Servletの処理に移る前にtomcatが実行する処理と思ってもらえればいいと思います。

このフィルターは、いくつも設定でき、順番に通っていきます。

ですので順番が重要なんです。



フィルターは、Filter インターフェースを継承すれば独自にいくつでも作成できます。

この中で、自分の処理が終わったら、次のフィルタに処理を渡すように作ります。




参考:

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

サーブレットフィルタ


tomcatでちょっと面倒なのは、リクエストの文字コードです。

文字コードは、ServletごとにHttpServletRequestの文字コードを設定しないといけません

正直、Servlet(またはController)を作成するたびに設定するのは骨が折れます。


1つの解決策としては、Servletの基底クラスを作ってその中で共通処理として文字コードを設定するという方法があると思います。

それでもいいかと思いますが、ここでは、web.xmlに設定する方法を見てみます。



【web.xmlファイルの記述】

  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
<filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>


※このフィルターは他のフィルターより前に書きます。(一番最初がいいと思います)
フィルターが分からない方は、こちら を参照ください。



【説明】
文字コードを設定するには、CharacterEncodingFilterを利用します。
paramとして、強制的に文字コードを変更するか?

文字コードを何にするか?を設定します。

そして、filter-mappingタグで、どのURLのときにこのフィルターを適用するかを設定します。

ここでは、/*を設定していて、ドキュメントルート以下すべてとなっています。



Springはこんなところもカバーしてるんですねー。




参考:

・フィルタとは?(tomcat)

・XMLとは?


SpringJDBCでDaoを作成したら、ビジネスロジックから呼び出したいです!

これをする方法を見てみます。


やることは単純で、Springの設定ファイルに設定するだけです。



【JavaのDaoクラス】

ここでは、MemberDaoImpl というクラスを作ったとします。

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



【Javaのビジネスロジックのクラス】

ここでは、MemberServiceImplというクラスを作ったとします。

以下のsetterをクラス内に用意しておきます。

public class MemberServiceImpl implements MemberService{
 private MemberDao memberDao;

public void setMemberDao(MemberDao memberDao) { this.memberDao = memberDao; }

public List<Member> findMember() { List<Member> memberList = this.memberDao.findMember(); return memberList; }

}





【Springの設定ファイル】

<bean id="memberService" class="business.service.MemberServiceImpl">
  <property name="memberDao" ref="memberDao"/>
 </bean>

<bean id="memberDao" class="dao.MemberDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean> <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>




【説明】

設定は上記のとおりです。

作成したMemberDaoImplをbeanに設定して、

それをさらにMemberServiceImplのmemberDaoプロパティに設定するだけです。



MemberServiceImplクラス内での実際のDao使い方は、見てのとおり!

インスタンスが設定されているものとして、普通に使うだけです。


 List<Member> memberList = this.memberDao.findMember();



これだけです!

インスタンスの生成とMemberServiceImplクラスへの設定はSpringがやってくれます。




前の記事にて、4つの連携方法をみました。

その中では、DelegatingActionProxyを使用する方法が良さそうという結論を出しました。


それでも、以下の弱点があることも書きました。


 1.Strutsのactionに設定するpathと同じidでSpring設定ファイルにActionクラスを設定しないといけません。

  ですので、1つパスが増えると2つのファイルに記述をしないといけないという問題があります。

 2.Springであれば、beanの使い回しができるのが当たり前ですが、beanのidをパス名と合わせない

  といけないです。ですので、同じActionクラスでも、path名が違えば、違うbeanとして設定しないといけません。 

 3.もうひとつ、beanのid名を自由に選べないという弱点もあります。



1を解決することはできませんが、2と3は解決できます。

その方法を見てみましょう。


一つ断っておくと、これは自分独自のやり方です。

Springなどでスタンダードなやり方は前の記事の4つのうちのどれかです。


でも、たぶん問題ないかとは思いますが、参考にするのは自己責任でラブラブお願いします。




【新たなProxyの作成】

以下のクラスを作ります。

StrutsのコンフィグファイルからBean名を取得するように変更しています。

import org.apache.commons.validator.GenericValidator;
import org.apache.struts.action.ActionMapping;
import org.springframework.beans.FatalBeanException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.struts.DelegatingActionProxy;
public class MyProxy extends DelegatingActionProxy { /** * actionタグのproertyタグ、parameter属性の値を順番に取得し、nullでない方をbean名として返す。 */ protected String determineActionBeanName(ActionMapping mapping) { //bean名の取得(propertyから) String beanName = mapping.getProperty("spring-bean"); if(!GenericValidator.isBlankOrNull(beanName)){ return beanName; } //propertyで見つからないとき、パラメターからbean名を取得 beanName = mapping.getParameter(); if(!GenericValidator.isBlankOrNull(beanName)){ return beanName; } //どちらからも見つからない場合 throw new FatalBeanException("struts-config error, " + "should set 'spring-bean' property or 'parameter' attibute."); } }




【Strutsファイルの設定】

Strutsのファイルには以下のようにset-propertyでSpringのbeanのidを設定する。

ここではtestActionというbeanを設定しています。


<action path="/test" type="MyProxy" scope="request" >
<set-property key="spring-bean" value="testAction"/>

</action>


【Springファイルの設定】

Springのファイルには以下のように、普通にbeanの設定をします。


<bean id="testAction" class="presentation.action.TestAction" />



もしくは、以下のようにスキャンを使って指定のパッケージ配下のクラスを自動でDIします。

この場合、bean名はクラス名の先頭を小文字にしたものになります。

これなら楽ですねにひひ


<context:component-scan base-package="presentation.action" annotation-config="false">
  <context:include-filter type="regex" expression=".*Action"/>
</context:component-scan>

  ※もちろんAction内のプロパティのDIは、@AutoWiredか@Resourceを使用します


【説明】

Strutsのactionタグのパス名とSpringのbean名が違うことが分かるでしょうか?

変わりに、actionのtype属性には先ほど作成したMyProxyを設定しています。


Springが提供するDelegatingActionProxy クラスは、機能拡張しやすいように機能をこまめにメソッドにしています。

determineActionBeanNameメソッドは、こまめに変更できるようにしたメソッドの一つで、Strutsに設定したパス名をmappingから取得し返却する役割を持っています。

このメソッドの呼び出し元では、返却されたパス名と同名のbeanをSpringのApplicationContextから取得する処理を行っています。

ですので、このメソッドを変更するだけで目的を達成できます!

これだけです。

でも、これにより、さまざまなことができます。

それは応用例で!


他にも機能を変更したい場合、DelegatingActionProxy クラスのソースを見てみましょう。

たいていの場合、やりたいことをオーバーライドするだけでできると思います。



【応用例】

例えば、MyProxyをさらに拡張してAという機能をつけたとしましょう。


そして、Strutsの設定ファイルに以下のように記述します

<action path="/extest" type="MyProxyA" scope="request" >
<set-property key="spring-bean" value="testAction"/>

</action>


すると、Springのbeanの設定の変更無くパスを追加できて、

しかもAという機能が付いた画面を提供できます。


再利用性が高まったでしょ?



参考:

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

Strutsと連携するには?(実践編)