Лучшая практика для асинхронной связи между службами - PullRequest
5 голосов
/ 29 марта 2012

Что лучше / хорошая практика привязки услуг / коммуникации в следующем сценарии (надеюсь, название несколько значимое):

Бизнес-уровень (BL), включающий несколько методов обслуживания, которые совместно используют (в качестве общей конечной точки связи) асинхронную службу сокетов (SS), которая может быть связана этими методами и используется для ввода-вывода сокетов.

например. BL захватывает SL и вызывает send (message), а затем ожидает ответа.

Сначала я использовал обратные вызовы и шаблон связывания. Поскольку у меня были некоторые проблемы с четким дизайном, использующим шаблон связывателя (отсутствие очереди сообщений и все, что делается в главном потоке), я сейчас пробую шаблон сообщений.

Таким образом, в основном службы BL и служба SL теперь имеют Messenger и соответствующий обработчик:

private final IncomingHandler incomingHandler = new IncomingHandler();
private final Messenger messengerReceiver = new Messenger(incomingHandler);
private class IncomingHandler extends Handler {
  @Override
  public void handleMessage(Message msg) {
  ...
  }
}

Один из BL - это подкласс AbstractAccountAuthenticator, реализующий

addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options){
     ...
     if(socketConnectionState != null){
        Bundle authBundle = new Bundle();
        authBundle.putString("password", password);
        authBundle.putString("username", account.name);
        Message message = Message.obtain(null, SocketConnectionHandler.SEND_REQUEST, authBundle);
        message.replyTo = messengerReceiver;
        socketConnectionState.getMessenger().send(message);
...}

, который также использует SL для получения authToken. Метод addAccount () либо требует немедленного возврата результата (authToken) в Bundle, либо вместо этого вызывает методы ответного обратного вызова. Теперь, если я запрашиваю токен аутентификации внутри addAccount через SL, как мне обработать, чтобы передать результат обратно?

Основная проблема здесь заключается в том, что результат возвращается не вызывающему методу (addAccount ()), а обработчику messengerReceiver.

Единственный способ, которым я мог придумать, - это BlockingQueue, которому предлагается обработчик сообщения, и который затем принимается внутри метода addAccount (), но на самом деле это выглядит грубо. Другие идеи? Правильный подход вообще?

1 Ответ

0 голосов
/ 04 апреля 2015

Ваша проблема возникает только в том случае, если вы указываете предпосылку, что ответ является проблемой обработчика сообщений.

У меня недавно была такая же проблема на работе.Мы решили эту проблему, расширив список аргументов обработчика сообщений

public interface MessageHandler {
    public void receivedMessage(Message message, ResponseChannel channel);
}

interface ResponseChannel {
    public void respond(Message response);
}

interface Message {}

. Конечно, можно было бы ввести переменную-член в каждом экземпляре MessageHandler, но это позволило бы устранить отсутствие состояния - в конце концов, принципоба подхода одинаковы.

Тем не менее, есть еще одна возможность.

Разделение интересов

Как я уже сказал, перед назначением дополнительной ответственности за ответ на ответ обработчику сообщений остается неприятный вкус.Обработчик сообщений уже отвечает за получение входящих сообщений.

Он обрабатывает входящее сообщение, что должно быть коротким процессом извлечения соответствующих параметров и пересылки сообщения заинтересованным сторонам или вызова соответствующих методов на модели или на контроллере.

Этодолжен быть коротким и неисчерпывающим процессом, потому что обработчики сообщений логически не являются частью компонента отправки / получения, а зарегистрированы там и совместно используют поток или пул потоков со всеми другими обработчиками сообщений и их вызовами.

Так как же тогда обращаться с ответами?Из этого следует, что, если это не входит в обязанности обработчиков, стороны, уведомленные обработчиком, должны предпринять действия.

public interface MessageHandler {
    public void receivedMessage(Message message, ApplicationContext context);
}

interface ApplicationContext {
    public void notifyUserJoined(String name);
}

interface Message {
    public String getUser();
}
...