struts2とseasar2を使ってアプリ作成(準備その2)~DI自動設定
前回の続き。
コンポーネントの自動登録(定義の自動生成)設定
前回までの話だと、アクションクラスをコンポーネントに登録(設定)する作業をアクションごとに行っていました。
また、前回はアクションクラスだけでしたが、DaoクラスやServiceクラスについても登録(設定)する必要が出てきます。
さすがにこれは手間なので、規約に従ったクラスを自動でコンポーネントとして登録するためにクリエータ(参考)を使用します。
Seasar2のdicon設定
まずはsrc/main/resourcesに下記の設定ファイルを追加。
- s2container.dicon
- creator.dicon
- customizer.dicon
s2container.dicon
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <include condition="#ENV == 'ut'" path="warmdeploy.dicon"/> <include condition="#ENV == 'ct'" path="hotdeploy.dicon"/> <include condition="#ENV != 'ut' and #ENV != 'ct'" path="cooldeploy.dicon"/> </components>
今回は常にcooldeploy.diconを使うように環境設定ファイルは作成しませんが、SMART deployを行う場合はここを見て設定。
creator.dicon
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <include path="convention.dicon"/> <include path="customizer.dicon"/> <component class="org.seasar.framework.container.creator.ActionCreator"/> <component class="org.seasar.framework.container.creator.DaoCreator"/> <component class="org.seasar.framework.container.creator.DtoCreator"/> <component class="org.seasar.framework.container.creator.DxoCreator"/> <component class="org.seasar.framework.container.creator.HelperCreator"/> <component class="org.seasar.framework.container.creator.LogicCreator"/> <component class="org.seasar.framework.container.creator.PageCreator"/> <component class="org.seasar.framework.container.creator.ServiceCreator"/> <component class="org.seasar.framework.container.creator.InterceptorCreator"/> <component class="org.seasar.framework.container.creator.ValidatorCreator"/> <component class="org.seasar.framework.container.creator.ConverterCreator"/> </components>
ひとまず、seasar2のzipファイルの中身のままで問題ないです。
customizer.dicon
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <include path="default-customizer.dicon"/> </components>
これもseasar2のzipファイルの中身のまま。
また、app.diconから下記の設定を除きます。
<component class="kamegu.action.SeasarTestAction" instance="prototype"/>
S2ContainerFilterの設定
上記の設定でも問題なく起動し、/myapp/seasar-testへのリクエストも問題なく処理されているように見えます。
しかし、SeasarTestActionに引数なしのコンストラクタを定義し、そこにブレークポイントを設定しデバッグ実行してみると初回リクエスト時にしかそこを通っていないことがわかります。
(コンストラクタが呼ばれているかを見たいので何かを標準出力させるだけでも十分です)。
理由はおそらく次のとおりです。
ここのクリエータ一覧を見るとActionCreatorのインスタンス属性=requestとなっており、その場合はS2ContainerFilterの設定が必要です。
S2ContainerFilter
この設定がないと、インスタンス属性=singletonで作成されてしまっているようです。
web.xml
下記の設定を追加します。ただし、StrutsPrepareAndExecuteFilterより前に書いてください
<filter> <filter-name>s2filter</filter-name> <filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class> </filter> <filter-mapping> <filter-name>s2filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
動作確認
他のクリエータも機能していることを確認するためにサービスクラスを作成します。
SeasarTestAction.java
package kamegu.action; import java.util.List; import javax.annotation.Resource; import kamegu.entity.Employee; import kamegu.service.HogeService; import org.seasar.extension.jdbc.JdbcManager; import com.opensymphony.xwork2.ActionSupport; public class SeasarTestAction extends ActionSupport { public List<Employee> employees; public String message1 = "seasar testです"; public HogeService hogeService; public HogeService hogeService1; @Resource(name="hogeService") public HogeService hogeService2; private HogeService hogeService3; @Resource(name="hogeService") private HogeService hogeService4; public SeasarTestAction seasarTestAction; public JdbcManager jdbcManager; public SeasarTestAction() { System.out.println(); } @Override public String execute() throws Exception { employees = jdbcManager.from(Employee.class).getResultList(); return SUCCESS; } }
これでアクセスすると毎回コンストラクタが呼ばれるようになっていることがわかると思います。
また、seasarTestActionフィールドとthisが同じオブジェクトであることもわかると思います。
(デバッグ実行でオブジェクトのidが同じことを確認、または、下記コードでチェック)
System.out.println((this == seasarTestAction));
また、HogeServiceのフィールドについてはhogeService, hogeService2, hogeService4にインジェクションされていることが分かります。
@Resourceアノテーションを使っていますが、@Bindingアノテーションでも同様です。参考
以下のようにしてもインジェクションされます。
@Resource private HogeService hogeService;
なお、ServiceCreatorのインスタンス属性=prototypeなので毎回作成され、hogeService, hogeService2, hogeService4は別オブジェクトです。
(singleton or protptypeの議論については別途。。。)
hogeService~seasarTestActionまでは今後不要なので削除しておいてください。
リクエスト時の警告メッセージについて
こういうメッセージが出る件
警告: kamegu.action.SeasarTestActionのプロパティ(container)が見つからないので設定をスキップします
やっぱり次回