Asynchronus Method Call Using AspectJ
非同期と継続と私 - 技術日記@kiwanamiを読んでいて、関数呼び出しを非同期化するのに、(funcall cc n)を(deferred:call cc n)に変更するだけで簡単にできるのが羨ましかったのでちょっと作ってみました(というだけです…)。
実装
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Async { Class<? extends Callback> callbackClass() default NullCallback.class; }
@Aspect public class AsyncSupport { @Pointcut("call(@net.wrap_trap.bitro.annotation.Async * *.*(..))") public void asyncCallPointcut(){}; @Around("asyncCallPointcut()") public Object doAsyncMethodCall(final ProceedingJoinPoint thisJoinPoint) throws Throwable{ final Callback callback = getCallback(thisJoinPoint); new Thread(new Runnable(){ @Override public void run() { try{ Object ret = thisJoinPoint.proceed(); if(callback != null){ callback.doCallback(ret); } }catch(Throwable t){ throw new RuntimeException(t); } } }).start(); return null; } private Callback getCallback(final ProceedingJoinPoint thisJoinPoint) { MethodSignature signature = (MethodSignature)thisJoinPoint.getSignature(); Async concurrent = signature.getMethod().getAnnotation(Async.class); return (Callback)ApplicationContainer.getContainer().getComponent( concurrent.callbackClass(), Scope.APPLICATION ); } }
実行
public class AsyncMethodCallTest { @Before public void setUp(){ ApplicationContainer.init(); ApplicationContainer.getContainer().registerComponent( DisplayResultCallback.class, new DisplayResultCallback(), Scope.APPLICATION ); } @Test public void testAsyncMethodCall() throws InterruptedException{ Target target = new Target(); target.add(1, 2); System.out.println("after call target.add(1,2)."); } static class Target{ @Async(callbackClass = DisplayResultCallback.class) public int add(int a, int b) throws InterruptedException{ Thread.sleep(10); System.out.println("called Target.add"); return a+b; } } static class DisplayResultCallback implements Callback{ @Override public void doCallback(Object result) { System.out.println("result: " + result); } } }