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);
        }
    }
}
結果

after call target.add(1,2).
called Target.add
result: 3

メソッドに@Asyncアノテーションを付けると非同期呼び出しになります。