Google App EngineにDWR2+SpringframeworkDI&AOPを乗せてみた
前回のログでは、Google App Engine(GAE)にSpringframeworkのDI(Dependency Injection)を乗せて、無事に動くことを見た。
今回は、Springframeworkの柱のもう一つである、AOP(Aspect Oriented Programing)を乗せてみる。AOPでWeavingするので、前回のサンプルプログラムは殆ど変更せず、jarの追加、Advisorの追加、定義ファイルの変更のみ行う。
Weavingするのは、メソッドの実行の前後でLog4jでクラス名とメソッド名をロギングするAdvice。
aopアライアンス(aop aliance)を使った以下のコードがそれである(注記:このコードはmezawa氏作成のものを流用させてもらった。ライセンスはApache License2.0でEzoGPプロジェクトに帰属するので注意願いたい)。これを、srcフォルダーのtestパッケージに作成する。
/* ********************************************************************** * $Id: MethodLogMarker.java 776 2009-05-20 18:20:37Z mezawa_takuji $ * * Takuji Mezawa( project: Syracava_EGP ) * * (C) 2008, EzoGP. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************** */ package test; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public final class MethodLogMarker implements MethodInterceptor { private static final Log log = LogFactory.getLog(MethodLogMarker.class); public Object invoke(MethodInvocation invocation) throws Throwable { String invokedClassName = invocation.getThis().getClass().getName(); String invokedMethodName = invocation.getMethod().getName(); /* メソッド開始のログメッセージを出力 */ log.info(markup(invokedClassName, invokedMethodName,true)); try { /* ウィービングされるオブジェクトメソッドの処理を実行する */ return invocation.proceed(); } finally { /* メソッド終了のログメッセージを出力 */ log.info(markup(invokedClassName, invokedMethodName, false)); } } /* * インターセプトした処理の前後にINFOメッセージを出力するための編集処理。 */ private String markup(String className, String methodName, boolean isStart) { StringBuilder message = new StringBuilder(); if (isStart) { message.append("STARTED "); } else { message.append("FINISHED "); } message.append(className).append(".").append(methodName); return message.toString(); } }
プロジェクトの作成と、jarのコピー
作業は、GAEプラグインがインストールされたEclipse3.4(Ganymede)で行った。
前回のログで作成したプロジェクト(GaeSpringFrameworkTest)をコピーして、新しいプロジェクトを作成する(GaeSpringFrameworkTest2)。
springダウンロードファイル(spring-framework-2.5.6.SEC01-with-dependencies.zip)に含まれる。
- spring-aspects.jar
- aopalliance.jar
- aspectjrt.jar
- aspectjweaver.jar
- cglib-nodep-2.1_3.jar
をwar/WEB-INF/libにコピーし、ビルドパスに追加する。
beans.xmlの変更
war/WEB-INF/beans.xmlにAOPの設定を追加する。具体的には、
を行う。ポイントカット(methodLogMarker)の定義では、testパッケージの全てのクラスの全てのメソッドの呼び出し、をWeavingの対象に設定した。
<?xml version="1.0" encoding="utf-8"?> <beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <bean id="demoBean" class="test.Demo"> <property name="helloMessages"> <ref bean="messages"/> </property> </bean> <util:map id="messages" map-class="java.util.HashMap"> <entry key="msg1" value="こんにちは! " /> <entry key="msg2" value="こんばんわ! " /> </util:map> <bean id="methodLog" class="test.MethodLogMarker" /> <aop:config> <!-- Definition of Pointcut--> <aop:pointcut id="methodLogMarker" expression="execution(* test..*(..))" /> <!-- Definition of Advisor --> <aop:advisor pointcut-ref="methodLogMarker" advice-ref="methodLog" /> </aop:config> </beans>
デプロイと実行
以上で、設定は終わりである。AOPのテストなので、Demo.javaといった既存のクラスを触ることはない。プロジェクトを選択し、「Google」->「Deploy to Web App Engine」でGAEにデプロイをする。以下が、これを実行した画面である。
以下が、GAEの管理コンソールでLogを参照したときの出力である。キチンとメソッドの開始と終了にロギングが埋め込まれている。
1点疑問は、ログを消すにはどうしたらいいのだろうということ。GAEではファイルシステムへのアクセスが制限されているので、ログも「お任せ」になっているが、AOPでこういうAdviceを滑り込ませると、相当のログを吐いてしまう。1回削除して再デプロイなのかなぁ。
(注記)
以前のログに書いたが、DWR2でscope=sessionと設定する際には注意が必要である。こう設定した場合、GAEは厳密にJavaBeanがシリアライズ可能であること(java.io.Serializableをimplしている)ことを求める。
上の例では、testパッケージの全てのメソッドにMethodLogMarker.javaでWeavingをかけているが、scope=sessionのJavaBeanにWeavingをかけると、MethodLogMarkerもSerializableをimplするように求めてくる。