不足:
工具类,获取mq连接
/**
* 获取MQ连接
* @return
* @throws IOException
* @throws TimeoutException
*/
public static Connection getConnection() throws IOException, TimeoutException {
//定义工厂
ConnectionFactory factory = new ConnectionFactory();
//服务地址
factory.setHost("127.0.0.1");
//AMQP端口
factory.setPort(5672);
//vhost
factory.setVirtualHost("/");
//用户密码
factory.setUsername("guest");
factory.setPassword("guest");
return factory.newConnection();
}
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();
}
出现队列
队列进行Get Message(s)
取出消息,Message变为0。
public class Consumer {
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("接收到的消息:" + msg);
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
public class Product {
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();
/**
* queue = QUEUE_NAME
* durable = false
* exclusive = false
* autoDelete = false
* arguments = null
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
for (int i = 0; i < 50; i++) {
String msg = "msg"+i;
System.out.println("product: "+msg);
/**
* exchange = ""
* routingKey = QUEUE_NAME
* props = null
* body = msg.getBytes()
*/
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
Thread.sleep(100);
}
channel.close();
connection.close();
}
}
线程睡眠时长不同
消费者一
public class Consumer1 {
private static final String QUEUE_NAME="test_work_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);
Consumer 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("消费消息:"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
System.out.println("[consumer1]-------------");
}
}
};
/**
* queue = QUEUE_NAME
* autoAck = true
* callback = consumer
*/
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
消费者二
public class Consumer2 {
private static final String QUEUE_NAME="test_work_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);
Consumer 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("c2: "+msg);
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
System.out.println("[consumer2]-------------");
}
}
};
/**
* queue = QUEUE_NAME
* autoAck = true
* callback = consumer
*/
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
autoAck
basicQos(perfetch=1)
每次请求一条消息,消费完之后,返回给队列,获取新的消息,可以实现处理快的消费者多处理。//增加代码,对消息进行控制
int prefetchCount = 1;
channel.basicQos(prefetchCount);
public class Product {
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();
/**
* queue = QUEUE_NAME
* durable = false
* exclusive = false
* autoDelete = false
* arguments = null
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//每个消费者发送确认消息前,消息队列不发在一个消息给消费者
int prefetchCount = 1;
channel.basicQos(prefetchCount);
for (int i = 0; i < 50; i++) {
String msg = "msg"+i;
System.out.println("product: "+msg);
/**
* exchange = ""
* routingKey = QUEUE_NAME
* props = null
* body = msg.getBytes()
*/
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
Thread.sleep(100);
}
channel.close();
connection.close();
}
}
增加语句
//开始的时候增加
channel.basicQos(1);
//处理消息时,手动回执
channel.basicAck(envelope.getDeliveryTag(),false);
public class Consumer2 {
private static final String QUEUE_NAME="test_work_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.basicQos(1);
Consumer 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("c2: "+msg);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
/**
* deliverTag = envelop.getDeliveryTag()
* multiple = false
*/
System.out.println("------------");
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
/**
* queue = QUEUE_NAME
* autoAck = true
* callback = consumer
*/
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
/**
* queue = QUEUE_NAME
* autoAck = true
* callback = consumer
*/
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
/**
* queue = QUEUE_NAME
* durable = false
* exclusive = false
* autoDelete = false
* arguments = null
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
生产者将消息发送给交换机而不是队列中,通过交换机(exchange)将消息发送到不同的队列。每个队列都要绑定到交换机上,消费者有自己的队列,以实现一个消息被多个消费者消费。
区别:
public class product {
private static final String EXCHANGE_NAME = "exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机
//fanout 分发
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
String msg = "hello exchange";
/**
* exchange = EXCHANGE_NAME
* routingKey = ""
* props = null
* body = msg.getBytes()
*/
channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());
System.out.println("Send: "+msg);
channel.close();
connection.close();
}
}
消费者中自己声明交换机(但是需要和生产者中的交换机相同),先启动消费者监听,防止交换机不存在报错
public class Consumer1 {
private static final String EXCHANGE_NAME = "exchange_fanout";
private static final String QUEUE_NAME = "queue_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
/**
* queue = QUEUE_NAME
* durable = false
* exclusive = false
* autoDelete = false
* arguments = null
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//消费者中自己声明交换机(但是需要和生产者中的交换机相同),先启动消费者监听,防止交换机不存在报错
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
//绑定队列到交换机
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
channel.basicQos(1);
boolean autoAck = false;
//直接匿名内部类,实现消费
channel.basicConsume(QUEUE_NAME,autoAck,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, StandardCharsets.UTF_8);
System.out.println("[1]Recv: "+ msg);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("---------");
//手动回执
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
});
}
}
Fanout
不处理路由键Direct
处理路由键routing key
交换机选择direct
类型,在进行消息转发时对比routing key
向值相同的队列转发消息。
消费者
channel.exchangeDeclare(EXCHANGE_NAME,"direct",true);
String msg = "direct msg sms";
//设置routing key
channel.basicPublish(EXCHANGE_NAME,"sms",null,msg.getBytes());
生产者
如果有多个routing key
多次进行绑定即可。
channel.exchangeDeclare(EXCHANGE_NAME,"direct",true);
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"email");
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"sms");
topic交换机将路由键和模式相匹配。将路由键切分成单词,用.
隔开,使用通配符进行表示#
匹配一个或多个单词,*
匹配一个单词
//匹配所有email开头的routingkey
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"email.#");