5

短い答えはノーかもしれませんが、別の提案が得られることを願っています。データ オブジェクトとデータ サービスがあるとします。データ サービスはインターフェイスであり、次のメソッドがあります。

public Data getData();

次の呼び出しハンドラーと Netty を使用してサービスのプロキシを作成し、非同期 rpc と呼ばれるものを実行しています。プロキシはクライアント側にあります。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // Convert the call into an async request that returns a ListenableFuture
    APCRequest request = new APCRequest(serviceType, method, args);
    ListenableFuture future = apcClient.asyncMessage(request);

    // This blocks until the future finishes
    return future.get();
}

これはうまくいきます。ただし、クライアントが UI の場合、サービス呼び出しを SwingWorker のようなものでラップすることになります。私はすでにそこに座っている ListenableFuture を返す方法を考え出したいと思います。別の非同期サービス API を作成せずにそれを達成する方法はありますか。例えば:

public ListenableFuture<Data> getData();

InvocationHandler に間違った型を返させることができれば、次のようなものを使用できます。

public abstract class AsyncServiceCall<S, D> { // S = service type, D = expected doCall return type
    protected final S service;

    protected AsyncServiceCall(Class<S> serviceType, APCClient client) {
        ProxyFactory proxyFactory = new ProxyFactory(client);

        // The true tells the proxyFactory we're expecting a ListenableFuture<D>
        // rather than the real return type.
        service = proxyFactory.createProxy(serviceType, true);
    }

    // Sub-classes would make a normal method call using this.  For
    // example, service.getData()
    public abstract Object doCall();

    @SuppressWarnings("unchecked")
    public ListenableFuture<D> execute() {
        return (ListenableFuture<D>) doCall();
    }

私が望むことを達成する別の方法はありますか?パフォーマンスは私にとって問題ではないので、プロキシが将来から戻り値を取得できるようになるまでブロックすることは、私が望むことを行う簡単な方法がない場合でもオプションです。とにかくUIで非同期呼び出しが必要なので、無駄に思えます。

サービス API をシンプルに保つことは、何よりも優先されます。サービス実装を直接インスタンス化する単純なサービス プロバイダーを使用してプロトタイプを作成し、動的プロキシを使用しているリモート プロトコル / サーバー / Netty を開発サイクルの後半にプラグインできるようにしたいと考えています。

4

1 に答える 1

3

API をシンプルに保ちたい場合は、インターフェイスで非同期 APIのみを提供することをお勧めします。非同期 API で同期実装をラップする方が、その逆よりもはるかに簡単です。

public interface DataService {
  public ListenableFuture<Data> getData();
}

public abstract class LocalDataService implements DataService {
  public ListenableFuture<Data> getData() {
    SettableFuture<Data> result = SettableFuture.create();
    try {
      Data theData = computeData();
      result.set(theData);
    } catch(Throwable t) {
      result.setException(e);
    }
    return result;
  }

  protected abstract Data computeData() throws Throwable;
}
于 2012-07-21T10:40:54.470 に答える