wicket-guiceでAOP
wicket-guiceでDIのサンプルはよく見るのですが、AOPをやってるサンプルはあまり見たことないのでやってみた。
このエントリーを参考にやらせていただきました。ありがとうございます。
下準備
wicket-guideでただ「HelloWorld!」を表示するだけのアプリです。これをもとにAOPの設定をしたいと思います。
public class WicketApplication extends WebApplication { public WicketApplication() { } public Class getHomePage() { return HomePage.class; } @Override protected void init() { addComponentInstantiationListener(new GuiceComponentInjector(this)); } }
public class HomePage extends WebPage { @Inject private Service service; public HomePage(final PageParameters parameters) { add(new Label("message", service.getMessage())); } }
@ImplementedBy(ServiceImpl.class) public interface Service { public String getMessage(); }
@Singleton public class ServiceImpl implements Service { public String getMessage() { return "Hello World!"; } }
アノテーションでやる方法
まず、アノテーションを作る。
@Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.METHOD }) @BindingAnnotation public @interface CalledLogging { // NOB. }
AOPアライアンスのMethodInterceptorをimplしてメソッドインターセプターを作る。
public class AroundLoggingInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { String methodName = invocation.getMethod().getDeclaringClass() .getName() + "#" + invocation.getMethod().getName(); System.out.println("start: " + methodName); // メソッド実行 Object returnObj = invocation.proceed(); // 終了ログ System.out.println("end: " + methodName); return returnObj; } }
ちなみにAOPアライアンスはmaven2から使う場合はpom.xmlに以下のように書いて依存関係を解決しとく。
<!-- AOPALLIANCE DEPENDENCIES --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency>
つぎにバインディング用のモジュールクラスを作って設定してあげます。わたしはWebApplicationのインナークラスで定義すれば良いかなと思います。
public class WicketApplication extends WebApplication { public WicketApplication() { } public Class<? extends WebPage> getHomePage() { return HomePage.class; } @Override protected void init() { addComponentInstantiationListener(new GuiceComponentInjector(this, getModule())); } protected Module getModule() { return new MyModule(); } static class MyModule extends AbstractModule { @Override protected void configure() { AroundLoggingInterceptor interceptor = new AroundLoggingInterceptor(); bindInterceptor(Matchers.any(), Matchers .annotatedWith(CalledLogging.class), interceptor); } } }
any()と、annotatedWith()が最初どこにあるか解らなかったのですが、com.google.inject.matcher.Matchersにあります。これはstatic importにしても良いと思います。
これで、あとはAOPしたいところに@CalledLoggingのアノテーションをつけていくだけです。
@Singleton public class ServiceImpl implements Service { @CalledLogging public String getMessage() { return "Hello World!"; } }
こんなのが出るとちゃんと動いている。
start: org.yamkazu.wicket.guice.service.ServiceImpl#getMessage end: org.yamkazu.wicket.guice.service.ServiceImpl#getMessage
アノテーションを使わずに、メソッド名とかで一括設定
AOP対象となるクラスの条件とAOP対象となるメソッドの条件を設定するクラスを作る。
public class ServiceClassMatcher extends AbstractMatcher<Class> { public boolean matches(Class clazz) { if (clazz.getName().endsWith("ServiceImpl")) { return true; } return false; } }
public class ServiceMethodMatcher extends AbstractMatcher<Method> { public boolean matches(Method t) { if (t.getName().endsWith("getMessage")) { return true; } return false; } }
こんどはWicketApplicationで以下のように設定してあげます。AroundLoggingInterceptorはアノテーションの設定で使ったものと同じものです。
public class WicketApplication extends WebApplication { public WicketApplication() { } public Class<? extends WebPage> getHomePage() { return HomePage.class; } @Override protected void init() { addComponentInstantiationListener(new GuiceComponentInjector(this, getModule())); } protected Module getModule() { return new MyModule(); } static class MyModule extends AbstractModule { @Override protected void configure() { bindInterceptor(new ServiceClassMatcher(), new ServiceMethodMatcher(), new AroundLoggingInterceptor()); } } }
このように設定してあげると今度は、ServiceImplでアノテーションを設定しなくても良くなります。
@Singleton public class ServiceImpl implements Service { public String getMessage() { return "Hello World!"; } }
ちゃんと動けば、さっきと同じようにこんなのが出ます。
start: org.yamkazu.wicket.guice.service.ServiceImpl#getMessage end: org.yamkazu.wicket.guice.service.ServiceImpl#getMessage