因为是我的书包,所以我喜欢JavaScript 。 实际上,我已经开始喜欢JavaScritp的面向异步回调的编程风格 。 因此,当我发现自己处于非JavaScript环境中时(例如Java) ,我往往会错过使用回调的机会。
好消息是您可以在Java中模拟异步回调。 实际上,我最近在一个我称为Ahoy的图书馆中做到了! ,这是适用于AWS的Java SQS库的异步SQS适配器 。
对于初学者来说, SQS是一个基于云的消息传递平台 –使用SQS,您可以创建队列并将消息放入这些队列,然后可以稍后或通过其他某个过程或相同的确切过程读取这些消息。 所有这些都利用Amazon的大规模冗余架构在面对并发访问时提供了极高的可用性。
Java中的异步回调可以通过两个功能实现:匿名类(包含一个方法)和Java的java.util.concurrent
包。
因为Java不允许您轻松地将函数(或方法)作为参数传递,以模拟回调,所以您可以创建一个包含一个方法的接口,该方法基本上模仿一个函数。 对于Ahoy,有两个接口: MessageSendCallback
和MessageReceivedCallback
–都有一个方法:分别是onSend
和onReceive
。 因此,Ahoy!的主要类被称为SQSAdapter
, SQSAdapter
公开了两个简单的方法: send
和receive
并且都采用了它们相关的回调接口。
要理解的最直接的回调是receive
方法。 可以想象, receive
是为了处理从特定队列接收到消息时的行为。 因此, receive
方法定义如下:
SQSAdapter的接收方法
public void receive(final MessageReceivedCallback callback) {}
MessageReceivedCallback
接口如下所示:
MessageReceivedCallback接口
public interface MessageReceivedCallback {public void onReceive(String messageId, String message);
}
请注意, onReceive
方法需要一个消息ID(特定于SQS)和消息本身-在SQS的情况下,它始终是一个String
(请记住, String
可以容纳您想要的任何内容:JSON,XML,字节序列)等)。
至此,客户淘! 在收到消息时提供消息的预期行为。 此行为可能是将某些内容写入数据库,生成另一条消息,然后将其发送到另一个队列(您命名)。
现在,有趣的部分是Ahoy!的receive
方法的实现。 为了实现异步性,我使用了Java的java.util.concurrent
包,可悲的是,它似乎不受欢迎。
接收方法的实现与回调被调用
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!客户端进行工作的示例,下面是一个测试用例,用于验证回调的执行:
接收方法已实现
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
方法中传递的onSend
,并传递新发送的消息的ID。
send方法也是异步的
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 确实提供了一个异步客户端 。 但是,此客户端的实现利用了Java的Futures 。 尽管Futures是一个简洁的概念 ,但Ahoy!的实现比Futures更方便( 至少对我来说以及我使用SQS的方式 ),因为一旦发送或接收消息,就不会涉及任何轮询。
虽然不一定在Java中本地支持回调,但是您可以很好地模拟它们并实现与JavaScript相同的代码简洁性。 而且,如果您需要方便的方法来与AWS SQS进行交互,请给Ahoy! 尝试一下 ! 你能挖出来吗,伙计?
翻译自: https://www.javacodegeeks.com/2013/10/ahoy-there-callbacks.html