Потому что это моя сумка, мне нравится JavaScript . На самом деле, я полюбил асинхронный стиль программирования JavaScritp, ориентированный на обратный вызов . Следовательно, когда я оказываюсь в среде, отличной от JavaScript, например, в Java , я склонен пропускать обратные вызовы. 
Хорошей новостью является то, что вы можете эмулировать асинхронные обратные вызовы в Java. Фактически, я сделал это недавно с библиотекой, которую я назвал Ахой! , который является асинхронным адаптером SQS для библиотеки AWS Java SQS .
Для непосвященных SQS представляет собой облачную платформу обмена сообщениями — с SQS вы можете создавать очереди и помещать сообщения в эти очереди, которые затем могут быть прочитаны — позже или немедленно каким-либо другим процессом или таким же точным процессом. Все это использует чрезвычайно избыточную архитектуру Amazon для обеспечения чрезвычайно высокой доступности при одновременном доступе.
Асинхронные обратные вызовы в Java могут быть реализованы с помощью двух функций: анонимных классов (содержащих один метод) и пакета Java java.util.concurrent .
Поскольку Java не позволяет вам легко передавать функции (или методы) в качестве параметра для имитации обратного вызова, вы можете создать интерфейс, содержащий один метод, который в основном имитирует функцию. В случае Ahoy есть два интерфейса: MessageSendCallback и MessageReceivedCallback — оба имеют один метод: onSend и onReceive соответственно. Соответственно, основной класс Ahoy!, SQSAdapter название SQSAdapter предоставляет два простых метода: send и receive и оба принимают соответствующий интерфейс обратного вызова.
Самый простой обратный вызов для понимания — это метод receive . Как вы можете себе представить, receive предназначено для обработки поведения, когда сообщение получено из определенной очереди. Таким образом, метод receive определяется следующим образом:
SQSAdapter метод получения
|
1
|
public void receive(final MessageReceivedCallback callback) {} |
Интерфейс MessageReceivedCallback выглядит следующим образом:
Интерфейс MessageReceivedCallback
|
1
2
3
|
public interface MessageReceivedCallback { public void onReceive(String messageId, String message);} |
Обратите внимание, что метод onReceive принимает идентификатор сообщения (который относится к SQS) и само сообщение, которое в случае SQS всегда является String (эта String может содержать все, что вы хотите, имейте в виду: JSON, XML, последовательность байтов , и т.д).
Таким образом, клиенты Ахой! обеспечить предполагаемое поведение сообщения при его получении. Такое поведение может быть для записи чего-либо в базу данных, создания другого сообщения и отправки его в другую очередь, вы называете это.
Теперь интересная часть — реализация метода receive Ahoy! Для достижения асинхронности я использовал Java-пакет java.util.concurrent , который, к сожалению, кажется недооцененным.
Реализация метода приема с обратным вызовом
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
private void receive(final AmazonSQS sqs, final String queueURL, final MessageReceivedCallback callback) { pool.execute(new Runnable() { public void run() { final List<Message> messages = sqs.receiveMessage( new ReceiveMessageRequest(queueURL).withMaxNumberOfMessages(10).withWaitTimeSeconds(20)).getMessages(); if (messages.size() > 0) { for (final Message message : messages) { callback.onReceive(message.getMessageId(), message.getBody()); sqs.deleteMessage(new DeleteMessageRequest(queueURL, message.getReceiptHandle())); } } } });} |
При фиксированном пуле потоков создается поток, который ожидает поступления сообщений в определенную очередь; когда он появляется, переданный в MessageReceivedCalledback вызывается для каждого сообщения.
Для примера того, как это работает для клиентов Ahoy !, вот тестовый пример, который проверяет выполнение обратного вызова:
Метод получения реализован
|
1
2
3
4
5
6
7
8
|
final boolean[] wasReceived = {false};ahoy.receive(new MessageReceivedCallback() { public void onReceive(String messageId, String message) { wasReceived[0] = true; assertNotNull("message id was null", messageId); assertEquals("message wasn't " + origMessage, origMessage, message); }}); |
Аналогично, отправка сообщения аналогична — создается новый экземпляр Runnable , который отправляет конкретное сообщение и вызывает переданный в MessageSentCallback onSend , передавая идентификатор вновь отправленных сообщений.
Метод отправки также является асинхронным
|
01
02
03
04
05
06
07
08
09
10
|
private void send(final AmazonSQS sqs, final String queueURL, final String message, final MessageSentCallback callback) { pool.execute(new Runnable() { public void run() { SendMessageResult res = sqs.sendMessage(new SendMessageRequest(queueURL, message)); if (callback != null) { callback.onSend(res.getMessageId()); } } });} |
Кстати, AWS Java SDK предоставляет асинхронный клиент ; однако реализация этого клиента использует Futures в Java. В то время как Futures — это опрятная концепция , реализация Ahoy! Более удобна ( по крайней мере для меня и в том, как я использую SQS ), чем Futures, так как после отправки или получения сообщения не происходит никакого опроса.
Хотя обратные вызовы не обязательно изначально поддерживаются в Java, вы можете довольно эмулировать их и достичь того же уровня краткости кода, что и в JavaScript. И если вам нужен удобный способ взаимодействия с AWS SQS, тогда дайте Ahoy! попробовать ! Ты можешь копать это, чувак?