maven依赖
生产者
public class RabbitProducer {
private static final String EXCHANGE_NAME = "exchange_demo ";
private static final String ROUTING_KEY = " routingkey_demo";
private static final String QUEUE_NAME = "queue_demo ";
private static final String IP_ADDRESS = "10.197.*.*";
private static final int PORT = 5672;//RabbitMQ 服务端默认端口号为5672
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost(IP_ADDRESS);
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
Connection con = connectionFactory.newConnection();
Channel channel = con.createChannel();
// 创建一个type="direct" 、持久化的、非自动删除的交换器
channel.exchangeDeclare(EXCHANGE_NAME, "direct" , true , false , null) ;
//创建一个持久化、非排他的、非自动删除的队列
channel. queueDeclare(QUEUE_NAME , true , false , false , null) ;
//将交换器与队列通过路由键绑定
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME ,ROUTING_KEY);
for(int i=0;i<1000000000;i++){
channel.basicPublish(EXCHANGE_NAME,ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN,(i+"message").getBytes());
System.out.println("message");
}
}
消费者
public class RabbitConsumer {
private static final String QUEUE_NAME = "queue_demo ";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("admin");
factory.setPassword("admin");
//这里的连接方式与生产者的demo 略有不同, 注意辨别区别
Connection connection = factory.newConnection(new Address[]{
new Address("10.197.*.*",5672)
}); // 创建连接
final Channel channel = connection.createChannel(); //创建信道
channel.basicQos(64); // 设置客户端最多接收未被ack 的消息的个数
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
System.out.println("recv message: " + new String(body));
/* try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(QUEUE_NAME, consumer);
//等待回调函数执行完毕之后, 关闭资源
/*TimeUnit.SECONDS.sleep(8);
channel.close();
connection.close();*/
}
注意: Channel channel = connection.createChannel();
一个连接可以有多个通道,做到多路复用。
channel不是线程安全的,不能在线程间共享。
exchange参数;
Exchange . DeclareOk exchangeDeclare(String exchange ,String type , boolean durable ,boolean autoDelete ,
boolean internal ,
Map arguments) throws IOException
type: 交换器类型,常用的有direct fanout topic
durable: 是否持久化
autoDelete: 自动删除 ,至少有一个队列或者交换器与之绑定,解绑后是否自动删除。
internal: 是否内置 设置为true时,客户端禁止使用,只能是交换器路由到该交换器。
arguments:结构化参数
Queue参数
Queue. DeclareOk queueDeclare (String queue , boolean durable , boolean exclusive,
boolean autoDelete, Map arguments) throws IOException
durable: 同上
exclusive: 是否排他 connection内共享,一旦创建后,其它connection也不能穿件同名排他队列,即使是持久化的,连接关闭后队列就会删除。
autoDelete:是否自动删除 至少有一个消费者连接到该队列,所有消费者断开后触发删除。
arguments: 结构化参数
注意:
生产者和消费者都能够使用queueDeclare 来声明一个队列,但是如果消费者在同一个
信道上订阅了另一个队列,就无法再声明队列了。必须先取消订阅,然后将信道直为"传输"
queueBind
Queue .bindOk queueBind(String queue , String exchange , String routingKey)
throws IOException ;
queue:队列名称
exchange:交换器名称
routingKey:绑定的路由键
消息发送:
void basicPublish(String exchange, String routingKey, boolean mandatory,
boolean immediate , BasicProperties props , byte[] body) throws IOException ;
mandatory: 当mandatory 参数设为true 时,交换器无法根据自身的类型和路由键找到一个符合条件
的队列,那么RabbitMQ 会调用Basic.Return 命令将消息返回给生产者。当mandatory 参
数设置为false 时,出现上述情形,则消息直接被丢弃。
immediate:
props;消息的基本属性集,其包含14 个属性成员,分别有contentType 、
content Encoding 、headers ( Map
correlationld 、replyTo 、expiration 、messageld、timestamp 、type 、userld 、
appld、clusterld。
basicPublish:
void basicPublish(String exchange, String routingKey, boolean mandatory,
boolean immediate , BasicProperties props , byte[] body) throws IOException ;
exchange:叫环器名称
routingKey:路邮键
props:消息的基本属性集,其包含14 个属性成员,分别有contentType 、
content E ncoding 、headers ( Map
correlationld 、replyTo 、expiration 、messageld、timestamp 、type 、userld 、
appld、clusterId
消费模式分为两种:
推模式:
Basic.Consume
String basicConsume(String queue , boolean autoAck, String consumerTag,
boolean noLocal , boolean exclusive, Map
throws IOException ;
autoAck:是否自动确认
consumerTag:消费者标签
noLocal : 设置为true 则表示不能将同一个Connectio口中生产者发送的消息传送给
这个Connection 中的消费者:
exclusive : 设置是否排他
arguments : 设置消费者的其他参数:
callback : 设置消费者的回调函数。用来处理Rabb itMQ 推送过来的消息,比如
DefaultConsumer , 使用时需要客户端重写(override) 其中的方法。
注意:
和生产者一样,消费者客户端同样需要考虑线程安全的问题。消费者客户端的这些callback
会被分配到与Channel 不同的线程池上, 这意味着消费者客户端可以安全地调用这些阻塞方
法,比如channel . queueDeclare 、channel . basicCancel 等。
每个Channel 都拥有自己独立的线程。最常用的做法是一个Channel 对应一个消费者,
也就是意味着消费者彼此之间没有任何关联。当然也可以在一个Channel 中维持多个消费者,
但是要注意一个问题,如果Channel 中的一个消费者一直在运行,那么其他消费者的callback
会被"耽搁"。
拉模式:
Basic.Get
GetResponse response = channel.basicGet(QUEUE NAME , false) ;
System.out.println(new String(response.getBody()));
channel .basicAck(response . getEnvelope() . getDeliveryTag() , false);