RabbitMQ的安装与基本使用(windows版)
基本结构

windows安装
1、 先安装erlang开发语言,然后安装rabbitmq-server服务器(需要比对rabbitmq版本和erlang版本对应下载安装,我项目中选用的版本为otp_win64_21.0.1.exe和rabbitmq-server-3.7.8.exe)
下载地址:链接:https://pan.baidu.com/s/1IyFYuSq_xNQivE33AA8YeQ 提取码:pl9g
2、 通过命令安装rabbitmq的web管理插件,rabbitmq-plugins enable rabbitmq_management(使用命令行在rabbitmq的安装目录下执行)
3、 使用http://localhost:15672打开web管理控制台,默认用户名和密码都是guest
4、 在web管理页面使用自定义用户进行开发,给予管理员权限,另外还需要为其配置数据库
工作模式
简单模式(一个生产者对应一个消费者)
1、模型

2、需要的依赖
<dependencies>
<!-- 引入队列依赖 -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.2</version>
</dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.10</version>
</dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency> <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
3、创建连接,分为消息发送方和消息消费方,不论哪一方都需要获取连接,创建通道,设置队列
4、连接工具类
public class ConnectionUtils {
/**
*功能描述 获取一个连接
* @date 2020/2/19
* @param []
* @return com.rabbitmq.client.Connection
*/
public static Connection getConnection() throws IOException, TimeoutException {
//定义一个连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置服务地址
factory.setHost("127.0.0.1");
//设置amqp端口
factory.setPort(5672);
//vHost
factory.setVirtualHost("/vHost_test");
//用户名
factory.setUsername("test");
//密码
factory.setPassword("123");
return factory.newConnection();
}
}
5、消息发送方
public class Send {
private static final String QUEUE_NAME = "test_simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
Channel channel = connection.createChannel();
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg = "hello simple";
channel.basicPublish("", QUEUE_NAME,null,msg.getBytes());
channel.close();
connection.close();
}
}
6、 消费者
public class Recei {
private static final String QUEUE_NAME = "test_simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
Channel channel = connection.createChannel();
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg= new String(body,"UTF-8");
System.out.println("receiver msg :" + msg);
}
};
//添加消费者监听
channel.basicConsume(QUEUE_NAME,consumer);
}
}
工作模式(一个生产者对应多个消费者,资源争抢)
模型

1、简单队列的不足:耦合性高,生产者和消费者一一对应,当队列名称变更,则需要同步变更
2、出现的原因:生产者发送消息是不怎么耗时的,而消费者消费消息是要进行处理业务的,因此耗时较高,这样当消息多了的情况下会导致消息积压,不利于消息处理
1、轮询分发
默认情况下,消息分发是通过轮询的方式分发的,不论消费者是否空闲,都是你一个我一个分发的
2、公平分发
需要手动确认分发,使用basicQos(prefetch = 1),需要关闭自动应答,改为手动
1、 生产者需设置消息发送间隔
2、 消费者除了设置消息发送间隔外,还需关闭消息自动应答
生产者
public class Send {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//创建通道
Channel channel = connection.createChannel();
//限制消息队列每次只能发送一条消息给消费者
//在消费者发送应答消息之前,消息队列不再发送消息给消费者
int prefetch = 1;
channel.basicQos(prefetch);
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
for (int i = 0; i < 50; i++) {
String msg = "test" + i;
System.out.println("work_queue send:" + msg);
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
Thread.sleep( i * 20);
}
channel.close();
connection.close();
}
}
消费者1
public class Recei1 {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
final Channel channel = connection.createChannel();
channel.basicQos(1);
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg= new String(body,"UTF-8");
System.out.println("R1 receiver msg :" + msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("R1 down");
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
boolean autoAck = false;//自动应答改为false
//添加消费者监听
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
消费者2
public class Recei2 {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
final Channel channel = connection.createChannel();
channel.basicQos(1);
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg= new String(body,"UTF-8");
System.out.println("R2 receiver msg :" + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("R2 down");
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
boolean autoAak = false;
//添加消费者监听
channel.basicConsume(QUEUE_NAME,autoAak,consumer);
}
}
效果:消费消息能力强的消费者将消费更多的消息,也称之为“能者多劳”使用线程休眠时间模拟处理消息的能力,时间越短表明处理消息的能力越强
消息应答和消息持久化
消息应答
boolean autoAck = false;
//添加消费者监听
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
消息持久化消息应答(autoAck),表示当消息队列发送消息给消费者之后,消费者发送消息应答给消息队列,收到应答后则会把消息从内存中删除,默认autoAck=true是打开自动应答的
//创建一个队列声明 Boolean durable = false;
channel.queueDeclare(QUEUE_NAME,durable,false,false,null);
订阅模式(publish/fanout)
说明:当已经声明了一个队列时,如果此时修改持久化状态,虽然代码不会提示出错,但是会运行失败,因为rabbitmq不允许重新定义一个已经存在的队列,此时可以从管理页面删除或重新定义一个新名称的队列
模型

1、 一个生产者,多个消费者
2、 每一个消费者都有自己的队列
3、 生成者没有直接把消息发送到队列上,而是发到了交换机,转换器 exchange
4、 每个队列都要绑定到交换机上
5、 生产者发送的消息经过交换机到达队列,这样就能实现一条消息由多个消费者消费
生产者:
public class send {
private static final String EXCHANGE_NAME = "test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");//分发
String msg = "hello exchange";
channel.basicPublish(EXCHANGE_NAME,"",null ,msg.getBytes());
System.out.println(msg);
channel.close();
connection.close();
}
}
消费者
public class Recei1 {
private static final String QUEUE_NAME = "test_pub_queue1";
private static final String EXCHANGE_NAME = "test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
Channel channel = connection.createChannel();
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg= new String(body,"UTF-8");
System.out.println("receiver msg :" + msg);
}
};
//添加消费者监听
channel.basicConsume(QUEUE_NAME,consumer);
}
}
Exchange(交换机 转换器)
一方面负责接收生产者发送的消息,另一方面是向队列推送消息
匿名转发 “”
Fanout(不处理路由),只要绑定了队列,就会把消息转给交换机上绑定的队列
Direct(路由模式),只有当交换机上设置的路由和消费者定义的路由一致时,交换机才会把消息转给绑定在交换机的消息队列
路由模式(routing/direct)
模型

1、 生产者声明交换机时定义模式为”direct”
2、 发布消息时带上routeKey
3、 消费者再声明队列后绑定交换机时带上设置的routeKey
只有队列上定义的key与交换机上设置的key相匹配时才会转发,只有当路由表明确时才有效果
生产者
public class Send {
private static final String EXCHANGE_NAME = "test_exchange_route";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
String routeKey = "sa";
String msg = "hello route";
channel.basicPublish(EXCHANGE_NAME,routeKey,null,msg.getBytes());
System.out.println("route msg:" + msg);
channel.close();
connection.close();
}
}
消费者
public class Recei1 {
private static final String QUEUE_NAME = "test_exchange_route1";
private static final String EXCHANGE_NAME = "test_exchange_route";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
Channel channel = connection.createChannel();
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"route");
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg= new String(body,"UTF-8");
System.out.println("receiver msg :" + msg);
}
};
//添加消费者监听
channel.basicConsume(QUEUE_NAME,consumer);
}
}
Topic模式
模型

匹配符匹配*,表示某一类的消息发送可以发送给消费者接收到
生产者
public class Send {
private static final String EXCHANGE_NAME = "test_exchange_topic";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME,"topic");
String msg = "goods....";
channel.basicPublish(EXCHANGE_NAME,"goods.delete",null,msg.getBytes());
System.out.println("topic send:" + msg);
channel.close();
connection.close();
}
}
消费者
public class Recei1 {
private static final String QUEUE_NAME = "test_exchange_topic1";
private static final String EXCHANGE_NAME = "test_exchange_topic";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//创建一个通道
Channel channel = connection.createChannel();
//创建一个队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"goods.add");
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg= new String(body,"UTF-8");
System.out.println("receiver msg :" + msg);
}
};
//添加消费者监听
channel.basicConsume(QUEUE_NAME,consumer);
}
}
效果:当消费者进行绑定时,设置routeKey为goods.*时,当生产者发送携带goods.*模式的routeKey时都可以被该消费者接收到
消息确认机制(事务+confirm)
在rabbitmq中,我们可以通过使用消息持久化机制解决当服务器异常导致消息丢失的问题
问题:当生产者把消息发出去之后,消息到底有没有到达rabbitmq服务器,这个默认情况是不知道的
解决方法:
1、 AMQP实现了事务机制
2、 Confirm模式
事务模式
txSelect,txCommit,txRollback,由AMQP中定义的三个api完成事务操作,三者分别为开启事务、事务提交、事务回滚
生产者:
public class Send {
private static final String QUEUE_NAME = "test_tx_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg = "hello tx";
try {
channel.txSelect();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
int i = 1/0;
channel.txCommit();
System.out.println("send:" + msg);
} catch (Exception e) {
channel.txRollback();
System.out.println("tx rollback");
}
channel.close();
connection.close();
}
}
消费者
public class Revei {
private static final String QUEUE_NAME = "test_tx_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.basicConsume(QUEUE_NAME,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body,"UTF-8");
System.out.println("recei msg:" + msg);
}
});
}
}
效果:当生产者发送消息时产生异常时,就会发生事务回滚,消费者也收不到该消息
缺陷:这种方式是比较耗时的,这样会降低消息的吞吐量
Confirm模式
生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,broker就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了,如果消息和队列是可持久化的,那么确认消息会将消息写入磁盘之后发出,broker回传给生产者的确认消息中deliver-tag域包含了确认消息的序列号,此外broker也可以设置basicack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理
此模式最大的好处就是可以异步
普通模式-单条发送
生产者
public class Send {
private static final String QUEUE_NAME = "test_confirm_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg = "hello confirm study";
channel.confirmSelect();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
if(!channel.waitForConfirms()) {
System.out.println("send confirm message fail:" + msg);
}else {
System.out.println("send confirm message ok:" + msg);
}
channel.close();
connection.close();
}
}
多条发送
生产者
public class Send {
private static final String QUEUE_NAME = "test_confirm_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg = "hello confirm study";
channel.confirmSelect();
for (int i = 0; i < 10; i++) {
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
}
if(!channel.waitForConfirms()) {
System.out.println("send confirm message fail:" + msg);
}else {
System.out.println("send confirm message ok:" + msg);
}
channel.close();
connection.close();
}
}
异步模式
Channel对象提供的ConfirmListener()回调方法只包含deliveryTag(当前Chanel发出的消息序号),我们需要自己为每个Channnel维护一个unconfirm的消息序号集合,每publish一条数据,集合中元素加1,每回调一次handleAck方法,unconfirm集合删掉相应的一条(multiple=false)或多条(multiple=true)记录,从程序运行效率上看,这个unconfirm集合最好采用有序集合SortedSet存储结构异步模式
生产者
public class Send1 {
private static final String QUEUE_NAME = "test_confirm_queue1";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//设置生产者的模式为confirm
channel.confirmSelect();
//存放未确认的消息标识
final SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>());
//添加监听
channel.addConfirmListener(new ConfirmListener() {
//成功回调方法
public void handleAck(long l, boolean b) throws IOException {
if(b) {
System.out.println("-----handleAck---multiple");
confirmSet.headSet(l + 1).clear();
} else {
System.out.println("-----handleAck---multiple false");
confirmSet.remove(l);
}
}
//失败回调方法
public void handleNack(long l, boolean b) throws IOException {
if(b) {
System.out.println("-----handleNack---multiple");
confirmSet.headSet(l + 1).clear();
} else {
System.out.println("-----handleNack---multiple false");
confirmSet.remove(l);
}
}
});
String msg = "hello confirm study";
while(true) {
long nextNo = channel.getNextPublishSeqNo();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
confirmSet.add(nextNo);
}
}
}
Spring整合rabbitmq
使用xml方式
依赖
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
Xml文件
<!--1、定义connection连接工厂-->
<rabbit:connection-factory id="connectionFactory"
host="127.0.0.1" port="5672" username="test" password="123"
virtual-host="/vHost_test" />
<!--2、定义rabbitmq模板,指定连接工厂以及exchange-->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" exchange="fanoutExchange"/>
<!--MQ的管理,包括队列,交换器声明等-->
<rabbit:admin connection-factory="connectionFactory"/
<!--定义队列自动声明-->
<rabbit:queue name="myQueue" auto-declare="true" durable="true" />
<!--定义交换器自动声明-->
<rabbit:fanout-exchange name="fanoutExchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="myQueue"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<!--队列监听-->
<rabbit:listener-container connection-factory="connectionFactory">
<rabbit:listener ref="foo" method="listen" queue-names="myQueue"/>
</rabbit:listener-container>
<!--消费者-->
<bean id="foo" class="com.hsz.rabbitmq.MyConsumer"/>
消费者
public class MyConsumer {
//业务代码
public void listen(String foo) {
System.out.println("监听到:" + foo);
}
}
测试
public class MyTest {
public static void main(String[] args) throws InterruptedException {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
RabbitTemplate bean = ctx.getBean(RabbitTemplate.class);
bean.convertAndSend("hello spring");
Thread.sleep(200);
ctx.destroy();
}
}
注解方式
依赖
<dependencies>
<!-- RabbitMQ的Java Client库 -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.amqp/spring-amqp -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-amqp</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.amqp/spring-rabbit -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
</dependencies>
rabbitmq.properties
#IP地址 rabbitmq.host=127.0.0.1 #端口号 rabbitmq.port=5672 #用户名 rabbitmq.username=test #密码 rabbitmq.password=123 #消费者监听的队列queue rabbitmq.queuenames=rabbitMQ_test2,rabbitMQ_pro_lswd_server,rabbitMQ_pro_lswd_wecaht #生产者监听消息queue rabbitmq.produce.queuename=rabbitMQ_pro_lswd_server #消息监听类 rabbitmq.listener.class=com.lswd.rabbitmq.listener.ServiceMessageListener
RabbitmqConfig配置文件
@EnableCaching
@PropertySource("classpath:db.properties")
public class RabbitmqConfig {
@Autowired
Environment env;
@Bean
<!-- 连接服务配置 -->
public ConnectionFactory connectionFactory(){
CachingConnectionFactory factory = new CachingConnectionFactory(
env.getProperty("rabbitmq.host"),
env.getProperty("rabbitmq.port", Integer.class)
);
factory.setUsername(env.getProperty("rabbitmq.username"));
factory.setPassword(env.getProperty("rabbitmq.password"));
return factory;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
RabbitAdmin rabbitAdmin=new RabbitAdmin(connectionFactory);
return rabbitAdmin;
}
@Bean
//AmqpTemplate配置,AmqpTemplate接口定义了发送和接收消息的基本操作
public AmqpTemplate rabbitTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate=new RabbitTemplate(connectionFactory);
RetryTemplate retryTemplate = new RetryTemplate();
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(500);
backOffPolicy.setMultiplier(10.0);
backOffPolicy.setMaxInterval(10000);
retryTemplate.setBackOffPolicy(backOffPolicy);
rabbitTemplate.setRetryTemplate(retryTemplate);
rabbitTemplate.setRoutingKey(env.getProperty("rabbitmq.produce.queuename"));
return rabbitTemplate;
}
@Bean
public ChannelAwareMessageListener channelAwareMessageListener() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (ChannelAwareMessageListener) Class.forName(env.getProperty("rabbitmq.listener.class")).newInstance();
}
@Bean
<!-- queue litener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象-->
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory,ChannelAwareMessageListener channelAwareMessageListener){
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
//container.setMessageListener(messageListener);
container.setChannelAwareMessageListener(channelAwareMessageListener);
Queue[] queues=new Queue[env.getProperty("rabbitmq.queuenames").split(",").length];
for (int i = 0; i < queues.length; i++) {
Queue queue=new Queue(env.getProperty("rabbitmq.queuenames").split(",")[i]);
queues[i]=queue;
}
container.setQueues(queues);
container.setConsumerArguments(Collections. <String, Object> singletonMap("x-priority",
Integer.valueOf(10)));
return container;
}
}
消息监听实现MessageListener
@Component
public class ServiceMessageListener implements MessageListener{//消息监听类虚实现MessageListener接口
@Override
public void onMessage(Message message) {
try {
//消息内容
String body = new String(message.getBody(), "UTF-8");
System.out.println("消息内容:::::::::::"+body);
//消息队列
System.out.println(message.getMessageProperties().getConsumerQueue());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
消息监听实现ChannelAwareMessageListener
@Component
public class ServiceMessageListener implements ChannelAwareMessageListener{
@Override
public void onMessage(Message message, Channel channel) throws Exception {
// TODO Auto-generated method stub
String body = new String(message.getBody(), "UTF-8");
System.out.println("消息内容:::::::::::"+body);
System.out.println(message.getMessageProperties().getConsumerQueue());
boolean mqFlag=false;//业务处理
//还有一个点就是如何获取mq消息的报文部分message?
if(mqFlag){
basicACK(message,channel);//处理正常--ack
}else{
basicNACK(message,channel);//处理异常--nack
}
}
//正常消费掉后通知mq服务器移除此条mq
private void basicACK(Message message,Channel channel){
try{
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}catch(IOException e){
System.out.println("通知服务器移除mq时异常,异常信息:"+e);
}
}
//处理异常,mq重回队列
private void basicNACK(Message message,Channel channel){
try{
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
}catch(IOException e){
System.out.println("mq重新进入服务器时出现异常,异常信息:"+e);
}
}
}
测试
@WebAppConfiguration
@RunWith(value = SpringJUnit4ClassRunner.class)
//指定spring配置类
@ContextConfiguration(classes = { WebConfig.class, AppConfig.class})
public class RabbitmqTest{
@Autowired
private AmqpTemplate rabbitTemplate;
@Test
public void pushMeun(){
MessageProperties properties= new MessageProperties();
properties.setConsumerQueue("rabbitMQ_test2");
rabbitTemplate.send(new Message("12.34".getBytes(), properties));
}
}
RabbitMQ的安装与基本使用(windows版)的更多相关文章
- TP-Shop安装步骤教程(Windows版)
TP-Shop安装步骤教程(Windows版) PS:首次发文,请多指教! 一.安装要求 1.PHP5.4以上,MYsql5.5以上. 2.需要Phpcurl,gd库.php_mysqli,php_o ...
- Nginx+Tomcat安装与配置(windows版)
相信很多人都听过nginx,这个小巧的东西慢慢地在吞食apache和IIS的份额.那究竟它有什么作用呢?可能很多人未必了解. 说到反向代理,可能很多人都听说,但具体什么是反向代理,很多人估计就不清楚了 ...
- node安装及配置之windows版
一.下载地址 https://nodejs.org/zh-cn/download/ https://nodejs.org/zh-cn/download/releases/ 二.安装步骤 1.双击“no ...
- PyCharm专业版安装(2018年Windows版)
友情提示: 本教程仅供学习交流使用,如需商业用途,强烈建议使用官方正式版.(官网正式链接为:https://www.jetbrains.com/pycharm/) 当然网上有很多其他激活教程,我看到的 ...
- Node.js安装详细步骤教程(Windows版)
什么是Node.js? 简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境: Node.js使用 ...
- nginx是什么nginx安装与配置之windows版
1.nginx是什么 为了快速了解nginx我们先引用网上的nginx介绍: Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP ...
- Apache下载、安装及配置(Windows版)
一.Apache的下载 1.点击链接http://httpd.apache.org/download.cgi,找到所需版本,如下图位置: 2.点击所需版本,选择Windows文件格式,如下图位置: 3 ...
- Node.js安装+环境配置【Windows版】
Node.js安装及环境配置之Windows篇 一.安装环境 1.本机系统:Windows 10 Pro(64位)2.Node.js:v6.9.2LTS(64位) 二.安装Node.js步骤 1.下 ...
- Python趣味入门02: 妥妥地安装配置Python(Windows版)
< 上一篇:Python趣味入门01:你真的了解Python么? 本篇内容手把手教您如何去网上下载安装Python的运行环境,本文写于2020年Python稳定的版本是3.8,Windows流行 ...
- bat-静默安装并配置mysql(windows版)
mysql版本 mysql-5.6.35-winx64 路径关系 @echo off Setlocal enabledelayedexpansion @REM vscode中自动开启延迟环境变量扩展, ...
随机推荐
- 腾讯云服务器CentOS 7.6安装基本中间件
腾讯云服务器CentOS 7.6安装基本中间件 摘要:由于最近开始学习Redis和Zookeeper了,因此使用云服务器的频率开始多了起来,并且开始了基础的安装教学,由于我之前确实没用过Linux ...
- BC4-牛牛学说话之-浮点数
题目描述 会说整数之后,牛牛开始尝试浮点数(小数),输入一个浮点数,输出这个浮点数. 输入描述 输入一个浮点数 输出描述 输出一个浮点数,保留三位小数 示例 1 输入:1.359578 输出:1.36 ...
- JavaScript 检查(Linting)工具的比较
一个好的检查(linting)工具可以确保一个项目遵循编码规范. 让我们来看看四种流行替代方案的特性和优缺点:JSLint , JSHint , JSCS 和 ESLint . JSLint JSLi ...
- 表单标签补充及css层叠样式
表单标签补充及css层叠样式 一.表单知识点补充 1.获取用户输入的标签两大重要属性 name属性:类似于字典的键 value属性:类似于与字典的值 # form表单朝后端发送数据的时候,标签必须得有 ...
- 论文翻译:2022_2022_TEA-PSE 2.0:Sub-Band Network For Real-Time Personalized Speech Enhancement
论文地址:TEA-PSE 2.0:用于实时个性化语音增强的子带网络 论文代码: 引用: 摘要 个性化语音增强(Personalized speech enhancement,PSE)利用额外的线索,如 ...
- 读Java8函数式编程笔记05_数据并行化
1. 并发 1.1. 两个任务共享时间段 1.2. 一个程序要运行两个任务,并且只有一个CPU给它们分配了不同的时间片,那么这就是并发,而不是并行 2. 并行 2.1. 两个任务在同一时间发生 2.2 ...
- LinkedHashmap简要说明
https://segmentfault.com/a/1190000012964859 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 H ...
- 10分钟搞定简易MVVM
实现一个简易的 MVVM 分为这么几步来 1.类 Vue:这个类接收的是一个 options. el属性:根元素的id data属性:双向绑定的数据. 2.Dep 类: subNode数组:存放所依赖 ...
- 【Raspberry Pi / 树莓派】小小工控机担起大大责任
CM4 Nano是一款基于Raspberry Pi / 树莓派 Compute Module 4(简称CM4),由EDATEC面向工业应用设计的嵌入式计算机, 充分利用CM4在结构上灵活性解决CPU, ...
- 搜索EE场景排序链路升级
作者:京东零售 吕豪 背景 EE(Explore & Exploit)模块是搜索系统中改善生态.探索商品的重要链路,其目标是缓解数据马太效应导致模型对商品排序丰富性.探索性不足,带来的系统非最 ...