本文是译文,原文请访问:http://www.rabbitmq.com/tutorials/tutorial-one-spring-amqp.html

RabbitMQ 是一个Brocker (消息队列服务器),它接受和转发消息 .

你可以将它当做邮局:

当你将要发布的邮件放在邮箱中时,您可以确定邮件先生或Mailperson女士最终会将邮件发送给您的收件人。在这个比喻中,RabbitMQ是邮箱,邮局和邮递员。

RabbitMQ和邮局之间的主要区别在于它不处理信纸,而是接受,存储和转发二进制大对象  blob(binary large object )数据 ——消息

0x01 RabbitMQ和一般的消息传递使用了一些术语

1. 生产者

生产者仅仅只是发送。一个发送消息的程序就是生产者:

2. 队列

队列是RabbitMQ中的邮箱的名称。虽然消息流经RabbitMQ和您的应用程序,但它们只能存储在队列中。甲队列仅由主机的存储器和磁盘限制约束,它本质上是一个大的消息缓冲器。

许多生产者可以发送到一个队列的消息,并且许多消费者可以尝试从一个队列接收数据。这就是我们代表队列的方式:

3. 消费者

消费这与生产者有类似的意义。一个消费者是一个程序,主要是等待接收信息:

请注意,生产者,消费者和代理不必驻留在同一主机上; 实际上在大多数应用中他们没有。应用程序既可以是生产者也可以是消费者。

0x02 官方 "Hello World"

2.1 (使用 spring-amqp client)

在本教程的这一部分中,我们将使用spring-amqp库编写两个程序; 发送单个消息的生产者,以及接收消息并将其打印出来的消费者。

我们将掩盖Spring-amqp API中的一些细节,专注于这个非常简单的事情才开始。它是消息传递的“Hello World”。

在下图中,“P”是我们的生产者,“C”是我们的消费者。中间的框是一个队列 - RabbitMQ代表消费者保留的消息缓冲区。

Spring AMQP框架

RabbitMQ说多种协议。本教程使用AMQP 0-9-1,它是一种开放的,通用的消息传递协议。RabbitMQ有许多不同语言的客户端 。

Spring AMQP利用Spring Boot进行配置和依赖管理。Spring支持maven或gradle,但在本教程中,我们将选择带有Spring Boot 1.5.2的maven

打开 http://start.spring.io/

提供:

  • group id (列如: org.springframework.amqp.tutorials)
  • artifact id (e.g. rabbitmq-amqp-tutorials)
  • 搜索 RabbitMQ依赖,然后选择 RabbitMQ 依赖

生成项目并将生成的项目解压缩到您选择的位置。

现在可以将其导入您喜欢的IDE中。或者,您可以从您喜欢的编辑器处理它。

2.2 配置项目

Spring Boot提供了许多功能,但我们只在这里强调一些。

首先,Spring Boot应用程序可以选择通过application.properties或application.yml文件提供其属性

编写application.properties

我们将在生成的项目中找到application.properties文件,其中没有任何内容。

添加application.properties 配置如下:

  1. spring.profiles.active=usage_message
  2. logging.level.org=ERROR
  3. tutorial.client.duration=10000

刚才配置文件中我们配置了一个

  1. tutorial.client.duration=10000

但是这个配置字段不存在于任何框架jar包里,因此我们需要编写一个类来处理这个属性

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.boot.CommandLineRunner;
  4. import org.springframework.context.ConfigurableApplicationContext;
  5.  
  6. public class RabbitAmqpTutorialsRunner implements CommandLineRunner {
  7.  
  8. @Value("${tutorial.client.duration:0}")
  9. private int duration;
  10.  
  11. @Autowired
  12. private ConfigurableApplicationContext ctx;
  13.  
  14. @Override
  15. public void run(String... args) throws Exception {
  16. // TODO Auto-generated method stub
  17. System.out.println("Ready ... running for " + duration + "ms");
  18. Thread.sleep(duration);
  19. ctx.close();
  20. }
  21.  
  22. }

接下来我们创建一个Java Config 文件(比如我们起名叫做 Tut1Config.java) 用来描述我们的Bean.

Tut1Config.java

  1. import org.springframework.amqp.core.Queue;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.context.annotation.Profile;
  5.  
  6. import com.xingyun.springamqp.business.Tut1Receiver;
  7. import com.xingyun.springamqp.business.Tut1Sender;
  8.  
  9. @Profile({"tut1","hello-world"})
  10. @Configuration
  11. public class Tut1Config {
  12.  
  13. @Bean
  14. public Queue hello() {
  15. return new Queue("hello");
  16. }
  17.  
  18. @Profile("receiver")
  19. @Bean
  20. public Tut1Receiver receiver() {
  21. return new Tut1Receiver();
  22. }
  23.  
  24. @Profile("sender")
  25. @Bean
  26. public Tut1Sender sender() {
  27. return new Tut1Sender();
  28. }
  29. }

通过上面这个配置类,我们做了四件事

  1. 首先通过 @Profile 注解,定义了 两个配置文件前缀别名,tut1 或者 hello-world
  2. 通过@Configuration 注解来让Spring 知道这是一个Java 配置文件
  3. 定义了 一个队列,名字叫做hello
  4. 另外定义了两个配置文件,一个叫做sender,一个叫做receiver

为什么要有这两个配置文件? 因为我们待会运行生产者和消费者的时候,可以通过动态加载不同的配置文件来启动不同的类。

比如我们启动生产者发布信息就可以调用这个配置:

  1. --spring.profiles.active=hello-world,sender
  1. 当我们想启动消费者就动态调用这个配置
  1. --spring.profiles.active=hello-world,receiver

接下来我们需要修改下整个应用程序的启动类:

  1. import org.springframework.boot.CommandLineRunner;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Profile;
  6. import org.springframework.scheduling.annotation.EnableScheduling;
  7.  
  8. import com.xingyun.config.RabbitAmqpTutorialsRunner;
  9.  
  10. @EnableScheduling
  11. @SpringBootApplication
  12. public class RabbitMq0x01SpringAmqpHelloWorldSampleApplication {
  13.  
  14. @Profile("usage_message")
  15. @Bean
  16. public CommandLineRunner usage() {
  17. return new CommandLineRunner() {
  18.  
  19. @Override
  20. public void run(String... arg0) throws Exception {
  21. System.out.println("This app uses Spring Profiles to control its behavior.\n");
  22. System.out.println("Sample usage: java -jar rabbit-tutorials.jar --spring.profiles.active=hello-world,sender");
  23. }
  24. };
  25. }
  26.  
  27. @Profile("!usage_message")
  28. @Bean
  29. public CommandLineRunner tutorial() {
  30. return new RabbitAmqpTutorialsRunner();
  31. }
  32.  
  33. public static void main(String[] args) {
  34. SpringApplication.run(RabbitMq0x01SpringAmqpHelloWorldSampleApplication.class, args);
  35. }
  36. }

当执行这个项目的jar 文件时会自动加载这个usage_message 配置,打印用法信息。

我们在启动类上添加@EnableScheduling,以便于开启对定时任务的支持

生产者

现在很少有代码需要进入发送方和接收方类。 我们称他们为Tut1Receiver和Tut1Sender。

Sender利用我们的配置和RabbitTemplate发送消息。

Tut1Sender.java

  1. import org.springframework.amqp.core.Queue;
  2. import org.springframework.amqp.rabbit.core.RabbitTemplate;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.scheduling.annotation.Scheduled;
  5.  
  6. public class Tut1Sender {
  7. @Autowired
  8. private RabbitTemplate template;
  9.  
  10. @Autowired
  11. private Queue queue;
  12.  
  13. @Scheduled(fixedDelay = 1000, initialDelay = 500)
  14. public void send() {
  15. String message = "Hello World!";
  16. this.template.convertAndSend(queue.getName(), message);
  17. System.out.println(" [x] Sent '" + message + "'");
  18. }
  19. }

您会注意到spring-amqp删除了样板代码,只留下了需要关注的消息传递逻辑。

我们在Tut1Config类中的bean定义中配置的队列中进行自动装配,并且像许多Spring连接抽象一样,我们使用可以自动装入发送器的RabbitTemplate包装样板rabbitmq客户端类。

剩下的就是创建一个消息并调用模板的convertAndSend方法,该方法从我们定义的bean和刚创建的消息中传入队列名。

Sending 不工作

如果这是您第一次使用RabbitMQ并且没有看到“已发送”消息,那么您可能会感到头疼,想知道可能出现的问题。 也许代理是在没有足够的可用磁盘空间的情况下启动的(默认情况下它至少需要200 MB空闲),因此拒绝接受消息。 检查代理日志文件以确认并在必要时减少限制。 配置文件文档将向您展示如何设置disk_free_limit。

Receiving  消费者

接收器同样简单。 我们用@RabbitListener注入我们的Receiver类并传入队列的名称。

然后,我们使用@RabbitHandler传入我们的receive方法,并传入已推送到队列的有效负载。

  1. import org.springframework.amqp.rabbit.annotation.RabbitHandler;
  2. import org.springframework.amqp.rabbit.annotation.RabbitListener;
  3.  
  4. @RabbitListener(queues = "hello")
  5. public class Tut1Receiver {
  6. @RabbitHandler
  7. public void receive(String in) {
  8. System.out.println(" [x] Received '" + in + "'");
  9. }
  10. }

整体来看

该应用程序使用Spring Profiles来控制它正在运行的教程,以及它是Sender还是Receiver。 选择使用配置文件运行的教程。 例如:

  1. - {tut1|hello-world},{sender|receiver}
  2. - {tut2|work-queues},{sender|receiver}
  3. - {tut3|pub-sub|publish-subscribe},{sender|receiver}
  4. - {tut4|routing},{sender|receiver}
  5. - {tut5|topics},{sender|receiver}
  6. - {tut6|rpc},{client|server}

当我们逐步完成其他五个教程时,我们将回到此列表。

在使用maven构建之后,运行应用程序但是您希望运行启动应用程序(例如,从ide或命令行)。

我们将展示如何从命令行运行。

查看用法

  1. java -jar RabbitMQ_0x01_SpringAMQP-0.0.1-SNAPSHOT.jar

启动生产者

  1. java -jar RabbitMQ_0x01_SpringAMQP-0.0.1-SNAPSHOT --spring.profiles.active=hello-world,sender

启动消费者

  1. java -jar RabbitMQ_0x01_SpringAMQP-0.0.1-SNAPSHOT.jar --spring.profiles.active=hello-world,receiver

Listing queues 列出队列

您可能希望看到RabbitMQ有哪些队列以及它们中有多少消息。 您可以使用rabbitmqctl工具(作为特权用户)执行此操作:

  1. sudo rabbitmqctl list_queues

在windows 电脑上去掉sudo

  1. rabbitmqctl.bat list_queues

生产[非]适用性免责声明

请记住,这个和其他教程都是教程。 他们一次展示一个新概念,可能会故意过度简化某些事情而忽略其他事物。

例如,为了简洁起见,在很大程度上省略了诸如连接管理,错误处理,连接恢复,并发和度量收集之类的主题。 这种简化的代码不应被视为生产就绪。

译: 1. RabbitMQ Spring AMQP 之 Hello World的更多相关文章

  1. 译: 2. RabbitMQ Spring AMQP 之 Work Queues

    在上一篇博文中,我们写了程序来发送和接受消息从一个队列中. 在这篇博文中我们将创建一个工作队列,用于在多个工作人员之间分配耗时的任务. Work Queues 工作队列(又称:任务队列)背后的主要思想 ...

  2. 译: 3. RabbitMQ Spring AMQP 之 Publish/Subscribe 发布和订阅

    在第一篇教程中,我们展示了如何使用start.spring.io来利用Spring Initializr创建一个具有RabbitMQ starter dependency的项目来创建spring-am ...

  3. 译: 6. RabbitMQ Spring AMQP 之 RPC

    Remote procedure call (RPC) 在第二篇教程中,我们学习了如何使用工作队列在多个工作人员之间分配耗时的任务. 但是如果我们需要在远程计算机上运行一个函数并等待结果呢?嗯,这是一 ...

  4. 译: 4. RabbitMQ Spring AMQP 之 Routing 路由

    在上一个教程中,我们构建了一个简单的fanout(扇出)交换.我们能够向许多接收者广播消息. 在本教程中,我们将为其添加一个功能 - 我们将只能订阅一部分消息.例如,我们将只能将消息指向感兴趣的特定颜 ...

  5. 译: 5. RabbitMQ Spring AMQP 之 Topic 主题

    在上一个教程中,我们提高了消息传递的灵活 我们使用direct交换而不是使用仅能够进行虚拟广播的fanout交换, 并且获得了基于路由key 有选择地接收消息的可能性. 虽然使用direct 交换改进 ...

  6. spring amqp rabbitmq fanout配置

    基于spring amqp rabbitmq fanout配置如下: 发布端 <rabbit:connection-factory id="rabbitConnectionFactor ...

  7. 深入剖析 RabbitMQ —— Spring 框架下实现 AMQP 高级消息队列协议

    前言 消息队列在现今数据量超大,并发量超高的系统中是十分常用的.本文将会对现时最常用到的几款消息队列框架 ActiveMQ.RabbitMQ.Kafka 进行分析对比.详细介绍 RabbitMQ 在 ...

  8. 消息中间件——RabbitMQ(九)RabbitMQ整合Spring AMQP实战!(全)

    前言 1. AMQP 核心组件 RabbitAdmin SpringAMQP声明 RabbitTemplate SimpleMessageListenerContainer MessageListen ...

  9. RabbitMQ与Spring的框架整合之Spring AMQP实战

    1.SpringAMQP用户管理组件RabbitAdmin. RabbitAdmin类可以很好的操作RabbitMQ,在Spring中直接进行注入即可.注意,autoStartup必须设置为true, ...

随机推荐

  1. C++对文本文件的读取和输出

    本文转载自xmh_free 自己浏览了上方的博客,主要整理了一下关于C++对文件的输入输出方法,如果想看C语言的输入输出方法,可浏览上述链接的博客 C++读写函数 在C++中,对文件的操作是通过str ...

  2. 全排列问题(递归&非递归&STL函数)

    问题描述: 打印输出1-9的所有全排序列,或者打印输出a-d的全排列. 思路分析: 将每个元素放到余下n-1个元素组成的队列最前方,然后对剩余元素进行全排列,依次递归下去. 比如:1 2 3 为例首先 ...

  3. pygame游戏开发入门例子

    # *_* coding:utf-8 *_* # 开发团队:中国软件开发团队# 开发人员:Administrator# 开发时间:2019/3/23 11:16# 文件名称:pygame_demo# ...

  4. How to uninstall Maya on a Mac

    How to uninstall Maya on a Mac Products and versions covered  By:  Support Jun 15 2018 SHARE ADD TO ...

  5. UVa 11059 - Maximum Product 最大乘积【暴力】

    题目链接:https://vjudge.net/contest/210334#problem/B 题目大意:Given a sequence of integers S = {S1, S2, . . ...

  6. canvas三角函数模拟水波效果

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  7. Java 复习

    基础: JAVA基础扎实,理解io.多线程.集合等基础框架,对JVM原理有一定的了解: 熟读Java SDK源码: 框架: 对Spring,ibatis,struts等开源框架熟悉:

  8. hibernate中多对一问题

    例如User类中有个Group引用对应数据库就是groupId的外键了. 外键映射成一个类对吧. <many-to-one name="groupId" column=&qu ...

  9. 【荐】详解 golang 中的 interface 和 nil

    golang 的 nil 在概念上和其它语言的 null.None.nil.NULL一样,都指代零值或空值.nil 是预先说明的标识符,也即通常意义上的关键字.在 golang 中,nil 只能赋值给 ...

  10. 菜鸟nginx源代码剖析数据结构篇(八) 缓冲区链表ngx_chain_t

    菜鸟nginx源代码剖析数据结构篇(八) 缓冲区链表 ngx_chain_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog. ...