2008/04/16からのアクセス回数 7743
Spring 2.0の特徴は、
ことです。
AopNameSpaceでは、普通のオブジェクト(以下POJOオブジェクトと呼びます)をAspectの Adviceとして使用することができます。
AopNameSpaceを使用するとAutoProxyCreatorは使用できないことに注意してください。
AopNameSpaceを使用するには、
が必要です。
いつものようにMVN Repositoryで検索すると、以下のようなdependecyタグが見つかりました。
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.5.4</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.4</version> </dependency>
これをpom.xmlに追加して、以下のコマンドを実行してください。
$ rm .project .classpath $ mvn eclipse:eclipse -DdownloadSources=true
AopNameSpaceを使った例を順を追って作成していきましょう。
Adviceとして使用するPOJOオブジェクトクラス(POJOAdvice)を以下のように定義します。
package org.springframework.showcase.aop;
public class POJOAdvice {
public void a() {
System.out.println("a called");
}
public void b(Long id) {
System.out.println("b(" + id +") called");
}
}
AopNameSpaceを使った定義ファイルは他のBean定義ファイルと別ファイルにすると 機能が切り分けられます。
aop-def.xmlは、以下のようになります。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="pojoAdvice" class="org.springframework.showcase.aop.POJOAdvice" />
<aop:config>
<aop:aspect ref="pojoAdvice">
<aop:before
method="a"
pointcut="execution(* *.findAll(..))" />
<aop:before
method="b"
pointcut="execution(* org.springframework.showcase.coverc.service.GenericHibernateDao.findById(..))
and args(id)"
/>
</aop:aspect>
</aop:config>
</beans>
'<aop:config>では、<aop:before>の他に以下の要素(タグ)が使用できます。
| 要素名 | 目的 |
| <aop:advisor> | AOP Advisorを定義します |
| <aop:after> | AOP after advice を定義します(正常・異常にかかわらずメソッドがreturnしたときに適応) |
| <aop:after-returning> | AOP after-return adivice を定義します |
| <aop:after-throwing> | AOP after-throwing advice を定義します |
| <aop:around> | AOP around advice を定義します |
| <aop:aspect> | aspectを定義します |
| <aop:before> | AOP before advice を定義します |
| <aop:pointcut> | pointcut を定義します |
'<aop:before>に戻って
します。 AspectJのpointcutは、
execution ( <戻り値のタイプ> <クラスパス>.<メソッド名>( [ <引数のタイプ> ] ) )
の形式で記述します。
aの場合のpointcutを見てみると
pointcut="execution(* *.findAll(..))"
とありますが、型、クラスパスに関係なくfindAllという名前のメソッドにpointcutを設定する 指定です。
次にbの場合のpointcutを見ると
pointcut="execution(* org.springframework.showcase.coverc.service.GenericHibernateDao.findById(..)) and args(id)"
and args(id)でfindByIdの引数idをbの呼び出しに渡すことを指定します。
aop-def.xmlを追加するために、web.xmlに以下のcontext-paramタグを追加します。
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext.xml /WEB-INF/aop-def.xml </param-value> </context-param>
前回のDefaultAdvisorAutoProxyCreatorを使ったAOPと共存できないので、applicationContext.xmlを 以下のように変更します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="recipeManager" class="org.springframework.showcase.coverc.service.StubRecipeDaoManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.postgresql.Driver</value>
</property>
<property name="url">
<value>jdbc:postgresql://localhost/springdb</value>
</property>
<property name="username">
<value>spring</value>
</property>
<property name="password">
<value>spring</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
</props>
</property>
<property name="mappingDirectoryLocations">
<list>
<value>classpath:/org/springframework/showcase/coverc/domain</value>
</list>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
</beans>
maven jettyプラグインを使って例題を実行します。
$ mvn jetty:run
次にブラウザーで
http://localhost:8080/mvc-convention/
と入力すると
a called a called
と表示されます。これは、RecipeManagerのfindAllとGenericHibernateDaoのfindAllの2カ所に pointcutが設定されたからです。
次に、ブラウザのaddリンクをクリックして「test」を入力した後、Save Changeボタンを押してください。 testがリストに追加されましたが、testのdeleteリンクをクリックしてください。
b(4) called a called a called
とb(4) calledが表示されます。bは、
org.springframework.showcase.coverc.service.GenericHibernateDao.findById
とクラスパスを指定しているので1回だけ表示されます。
AopNameSpaceを使ったAOPでは、引数を明示的に指定する必要があり、ログ出力のような チェックプリントのメソッドを実行することができません。
チェックプリントは、デバッガでは追えない並行処理のデバッグに有効な手段です。
ここでは、ログ出力とAopNameSpaceの併用の方法について説明します。
チェックプリントを出力したいBeanをProxyFactoryBeanでラップすることで 指定したBeanにログ出力機能を加えることができます。
<bean id="enterMethodLogAdvice" class="org.springframework.showcase.aop.EnterMethodLogAdvice"/> <bean id="leaveMethodLogAdvice" class="org.springframework.showcase.aop.LeaveMethodLogAdvice"/> <bean id="logBase" abstract="true"> <property name="interceptorNames"> <list> <value>enterMethodLogAdvice</value> <value>leaveMethodLogAdvice</value> </list> </property> </bean> <bean id="recipeManager" class="org.springframework.aop.framework.ProxyFactoryBean" parent="logBase"> <property name="target"> <bean class="org.springframework.showcase.coverc.service.StubRecipeDaoManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </property> </bean>
先ほどと同様に実行すると、
a called enter findAll args=() a called leave findAll return=[org.springframework.showcase.coverc.domain.Recipe@9ab468, org.springframework.showcase.coverc.domain.Recipe@a06db5, org.springframework.showcase.coverc.domain.Recipe@82aacf] -- 途中省略 enter save args=(org.springframework.showcase.coverc.domain.Recipe@fbe09b) leave save return=null a called enter findAll args=() a called leave findAll return=[org.springframework.showcase.coverc.domain.Recipe@82c6dc, org.springframework.showcase.coverc.domain.Recipe@cdb92b, org.springframework.showcase.coverc.domain.Recipe@37bc9e, org.springframework.showcase.coverc.domain.Recipe@403477] enter findById args=(4) b(4) called leave findById return=org.springframework.showcase.coverc.domain.Recipe@108172 enter delete args=(org.springframework.showcase.coverc.domain.Recipe@108172) leave delete return=null a called enter findAll args=() a called leave findAll return=[org.springframework.showcase.coverc.domain.Recipe@6b2d99, org.springframework.showcase.coverc.domain.Recipe@7ec7b9, org.springframework.showcase.coverc.domain.Recipe@6a56f0]
のようにログ出力とAopNameSpaceの出力の両方が出ています。
Spring-MVC/ステップ・バイ・ステップ/AOPの追加の
今回使用したファイルは、以下にあります。
この記事は、
皆様のご意見、ご希望をお待ちしております。