RabbitMQ简单使用
测试用例,比较简陋,菜鸟一个,欢迎指出不足
1、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、创建工具类
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class MqConnectionUtils {
public static Connection getConnection() throws IOException, TimeoutException {
//创建连接对象
ConnectionFactory factory = new ConnectionFactory();
//主机地址 自己服务器搭的,本地没有环境的,可以简单用用
factory.setHost("47.96.186.103");
//端口
factory.setPort(5672);
//设置虚拟主机名
factory.setVirtualHost("zhenxu");
factory.setUsername("zhenxu");
factory.setPassword("zhenxu");
return factory.newConnection();
}
}
3、创建生产者
生产者这里分了 普通的 ,和消息发布确认的
1)普通
生产者
@GetMapping("/test1")
public void test1() throws IOException, TimeoutException {
Connection connection = MqConnectionUtils.getConnection();
Channel channel = connection.createChannel();
/**
* 声明队列
* 参数1:消息队列名称
* 参数2,是否持久化
* 参数3,是否独占本次connection链接
* 参数4,是否自动删除消息
* 参数5,是否需要传递额外的队列数据Map
*/
channel.queueDeclare("test01", true, false, false, null);
long begin = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
String msg = i + "";
/**
* 发布消息
* 参数1,使用指定的交换机,不设置则使用默认交换机
* 参数2,指定路由器key,如果是简单模式直接给队列名就行
* 参数3,发生消息时是否需要额外的消息数据
* 参数4,消息内容
*/
channel.basicPublish("", "test01", null, msg.getBytes());
}
long end = System.currentTimeMillis();
System.out.println("发布条数:1000,耗时:" + (end - begin) + "ms");
//关闭资源
channel.close();
connection.close();
}
消费者公用
import com.example.demo.rabbitMq.utils.MqConnectionUtils;
import com.rabbitmq.client.*;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
@Component
public class consumerTest01 {
@Bean
public void test01() throws IOException, TimeoutException {
Connection connection = MqConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare("test01", true, false, false, null);
/** 创建消费者 */
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//实现消费的业务逻辑
/*System.out.println("consumerTag" + consumerTag);
System.out.println("交换机:" + envelope.getExchange()
+ "------RoutingKey" + envelope.getRoutingKey()
+ "-----DeliveryTag:" + envelope.getDeliveryTag()
);*/
System.out.println("消息本身:" + new String(body, "UTF-8"));
}
};
/**
* 监听消息
* 参数1,指定要监听的队列的名称
* 参数2,设置消息的应答模式,true自动应答(性能好,消息有可能丢失),false手动应答
*
*/
channel.basicConsume("test01", true, defaultConsumer);
}
}
2)消息发布确认
1>单个 和 批量 确认模式
1、单个确认模式 效率很慢。适合吞吐量很小的
2、批量确认模式,与单个相比,可以极大地提高吞吐量。但缺点很明显,当有故障时,无法定位那个消息出问题了。这种方案仍然是同步的。
@GetMapping("/test2")
public void test2() throws IOException, TimeoutException {
Connection connection = MqConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//生产者 信道开启发布确认
channel.confirmSelect();
/**
* 声明队列
* 参数1:消息队列名称
* 参数2,是否持久化
* 参数3,是否独占本次connection链接
* 参数4,是否自动删除消息
* 参数5,是否需要传递额外的队列数据Map
*/
channel.queueDeclare("test01", true, false, false, null);
long begin = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
String msg = i + "";
/**
* 发布消息
* 参数1,使用指定的交换机,不设置则使用默认交换机
* 参数2,指定路由器key,如果是简单模式直接给队列名就行
* 参数3,发生消息时是否需要额外的消息数据
* 参数4,消息内容
*/
channel.basicPublish("", "test01", null, msg.getBytes());
try {
/** todo 加这个就是批量,不加就是单个。批量缺点:批量有错误的话,不知道是哪个 */
// if (i % 100 == 0) {
boolean b = channel.waitForConfirms();
if (b) {
System.out.println("消息发送成功");
}
}
} catch (InterruptedException e) {
System.out.println("消息发送失败");
throw new RuntimeException(e);
}
}
long end = System.currentTimeMillis();
System.out.println("发布条数:1000,耗时:" + (end - begin) + "ms");
//关闭资源
channel.close();
connection.close();
}
2>异步模式
效率最好,性价比最高,最常用
/**
* 异步确认 性价比最高,可靠性和效率都没得说
* 利用回掉函数来达到消息可靠性传递的
*/
@GetMapping("test5")
public void test5() throws IOException, TimeoutException {
Connection connection = MqConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare("test01", true, false, false, null);
//开启发布确认
channel.confirmSelect();
//开始时间
long begin = System.currentTimeMillis();
//消息成功回调函数
ConfirmCallback ackCallback = (deliveryTag, multiple) -> {
System.out.println("确认消息:" + deliveryTag);
};
//消息失败回调函数
ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
System.out.println("未确认消息:" + deliveryTag);
};
channel.addConfirmListener(ackCallback, nackCallback);
for (int i = 0; i < 1000; i++) {
String msg = i + "";
channel.basicPublish("", "test01", null, msg.getBytes());
}
//结束时间
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - begin) + "ms");
}