服务之间的同步调用,可使用 HTTP 或 RPC 来完成,但并不是全部的调用都须要同步,有些场景下,当客户端调用服务端时,并不须要等待服务端作出响应,此时就应该使用异步调用。异步调用的经常使用方式是基于 MQ (Message Queue) 来实现的。下文会以 ActiveMQ 为例进行讲解。java
ActiveMQ 是 Java 世界中最为流行的开源消息中间件,它不只功能强大,并且性能稳定。它可全面支持 JMS(Java 消息服务)技术规范,为 Java 应用程序提供标准的 JMS API。web
此外 ActiveMQ 具有与 Spring 框架整合的能力,它一直都是 Spring 应用程序的消息中间件标配。一样, Spring Boot 也提供了 ActiveMQ 的开箱即用的插件,只须要几项配置,就能接入 ActiveMQ,并轻松使用 JMS API 编写异步消息通讯程序。spring
Active MQ 官网地址以下docker
http://activemq.apache.orgshell
先使用 docker 安装 ActiveMQ ,目前 ActiveMQ 官方并未提供相应的 Docker 镜像,咱们选择使用第三方镜像 webcenter/activemq
。apache
docker pull webcenter/activemq:5.14.3
接下来运行 ActiveMQ浏览器
docker run -d -p 8161:8161 -p 61616:61616 -e ACTIVEMQ_ADMIN_LOGIN=admin -e ACTIVEMQ_ADMIN_PASSWORD=admin --name activemq webcenter/activemq:5.14.3
在启动 ActiveMQ 容器时,容器对宿主机暴露了两个端口号:springboot
此外,在启动 ActiveMQ 容器时,还提供了两个环境变量服务器
webcenter/activemq
镜像拥有一个基于 Web 的控制台,可经过浏览器访问。容器启动完毕后,能够打开浏览器,并在地址栏中输入 http://localhost:8161
点击 Manage ActiveMQ borker 连接,浏览器将弹出一个对话框,此时输入用户名和密码,认证经过后会进入管理界面
在管理界面中,包括 8 个功能菜单
ActiveMQ 管理了两类消息通道,一类是队列(Queue),另外一类叫作主题(Topic)。
Queue 用于解决消息的 点对点 通讯问题,也就是说,消息从生产者(Producer) 发出后,首先进入 ActiveMQ 某个指定的 Queue 中,而后再将消息传送给其中一个消费者(Consumer)。
Topic 用于解决消息的发布与订阅(Publish-subscribe) 通讯问题,也就是说,消息从 Producer 发出后,首先将其发布到 ActiveMQ 某个指定的 Topic 上,而后将此消息分发给每一个订阅者(Subscriber) 。
在具体场合下,灵活使用以上两种通讯模式来实现 Producer 与 Consumer/Subscriber 间的异步调用,从而解决调用方的耦合问题。可见,Queue 能解决调用缓冲问题,Topic 能解决消息广播问题, Queue 与 Topic 都能解决掉调用耦合问题,这些技术都为一个好的软件架构提供了有效的支撑。
下面就以 Queue 为例,将 ActiveMQ 与 Spring Boot 进行整合,将 Producer 做为客户端, Consumer 做为服务端,经过 Queue 实现客户端与服务端的异步调用
首先建立一个名为 acitvemq-hello-server
的 spring boot 项目,若是在 eclipse 中安装了 Spring Tools ,能够在新建时选择 New Spring Starter Project
选项。或者新建 Maven 工程。对应的 maven 依赖以下
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.19.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId> </dependency> </dependencies>
在 Spring Boot 框架中已经内置了对 ActiveMQ 的支持,咱们只须要依赖 spring-boot-starter-mq 就能启动 ActiveMQ,此时还须要在 application.properties
文件中添加 ActiveMQ 配置项
spring.activemq.broker-url=tcp://10.104.10.1:61616 spring.activemq.user=admin spring.activemq.password=admin
接下来建立 HelloServer
的类,封装服务端相关代码
@Component public class HelloServer { @JmsListener(destination="hello-queue") public void receive(String message) { System.out.println(message); } }
使用 @Component
注解,说明它可被 Spring IoC 容器所管理。此时只须要使用 @JmsListener
注解,并将其绑定到 receive()
方法上,就能从 ActiveMQ 中接收响应的消息。
@JmsListener
注解中须要添加一个 destination 属性来指定 Queue/Topic
的名称,该名称具备惟一性。消息将以一个 String 类型参数的形式传入方法体中,也能够接收其余类型的消息,这取决于客户端发送的消息是哪一种类型。Spring JMS 将消息放入 ActiveMQ 时会进行序列化,当消息从 ActiveMQ 取出时将进行反序列化,应用程序无需关注这些底层细节,只须要将精力放在业务逻辑上。
最后,编写一个 Spring Boot 应用程序启动类来启动服务端(使用 spring tools 工具会自动生成)
@SpringBootApplication public class ActivemqHelloServerApplication { public static void main(String[] args) { SpringApplication.run(ActivemqHelloServerApplication.class, args); } }
当服务端启动完毕后,将一直监听 ActiveMQ 的 hello-queue 队列中即将到来的消息,消息由客户端来发送。
建立一个名为 active-mq-client
的 Maven 项目, pom.xml 文件内容与服务端类似。application.properties 文件与服务端相同。
接下来建立一个名为 HelloClient
的类,将其做为客户端。
@Component public class HelloClient { @Autowired private JmsTemplate jmsTemplate; public void send(String message) { jmsTemplate.convertAndSend("hello-queue", message); } }
这里使用了 @Autowired
注解, JmsTemplate 对象注入进来,还编写了一个 send()
方法,在该方法中调用 JmsTemplate 对象的 convertAndSend
来转换并发送消息。
最后使用 Spring Boot 应用程序启动类来启动客户端
@SpringBootApplication public class ActivemqHelloClientApplication { @Autowired private HelloClient helloClient; @PostConstruct public void init() { helloClient.send("hello world"); } public static void main(String[] args) { SpringApplication.run(ActivemqHelloClientApplication.class, args); } }
须要注意的是, init()
方法带有 @PostConstruct
注解,表示 Spring IoC 容器实例化 ActivemqHelloClientApplication
类后将调用该方法。
运行 main() 方法能够启动客户端应用程序,并能够在服务端应用程序控制台中看到 client 发送的消息,也能够在 ActiveMQ 控制台中查看队列的当前状态
Queue 表格中列明的含义以下
此外,还有下面几种操做