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中自动开启延迟环境变量扩展, ...
随机推荐
- 数据结构与算法 -> 大顶堆与小顶堆
一.大顶堆 大顶堆是一种数据结构,它是一颗完全二叉树,并且满足以下性质: 每个节点的值都大于或等于它的子节点的值 因此,大顶堆的根节点(也称为堆顶)总是最大的元素 二.小顶堆 小顶堆也是一种数据结构, ...
- MySQL 删除数据 批量删除(大量)数据
在删除数据的时候根据不同的场景使用不同的方法,比如说删除表中部分数据.删除表的结构.删除所有记录并重置自增ID.批量删除大量数据等,可以使用delete.truncate.drop等语句. 一.方法分 ...
- px批量转vw方法,适用于用户临时突发自适应需求,快速搞出项目多屏幕适应方案postcss-px-to-viewport,postcss.config.js配置
方案一: 1. 下载依赖 npm install postcss-import postcss-loader postcss-px-to-viewport --save-dev npm install ...
- Java 进阶P-11+P-12
文本流 在流上建立文本处理 PrintWriter pw = new PrintWriter()( new BufferedWriter( new Out put StreamWriter( new ...
- 【开源】libinimini:适用于单片机的极简 ini 解析库
介绍说明 最近自己基于 XR872 在做一个小作品练习练习,具备可以配置的功能,选择了使用 ini 作为配置文件.我调研了网上常见的 ini 解析库,几乎都涉及到了 fopen()/fgets().. ...
- Performance API不完全使用指北
本教程解释了如何使用Performance API来记录真实用户访问你的应用程序的统计数据. 使用浏览器的DevTools来评估web应用性能是很有用的,但要复现现实世界的使用情况并不容易.因为人们在 ...
- 10月31日ATM编写逻辑描述
目录 ATM逻辑描述 三层框架简介 1.第一层(src.py) 2.第二层(interface文件夹下内容) 3.第三层(db_hanlder) 启动函数 用户注册功能 用户登录 common中的小功 ...
- 使用 LoRA 进行 Stable Diffusion 的高效参数微调
LoRA: Low-Rank Adaptation of Large Language Models 是微软研究员引入的一项新技术,主要用于处理大模型微调的问题.目前超过数十亿以上参数的具有强能力的大 ...
- 强大的Excel工具,简便Vlookup函数操作:通用Excel数据匹配助手V2.0
通用Excel数据匹配助手V2.0 For Windows 通用Excel数据匹配助手是一款非常实用的数据匹配软件,可以用来代替Excel中的Vlookup函数,帮助用户轻松完成数据匹配操作,需要的朋 ...
- 与ChatGPT关于测试问题的对话
1测试人员创造什么价值? 测试人员在软件开发生命周期中扮演着非常重要的角色,他们的主要职责是确保软件在发布前达到高质量标准.以下是测试人员为软件开发和业务提供的价值: 1.缺陷检测和修复:测试人员的主 ...