1 连接 (消费者和接受者都需要使用)
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("127.0.0.1");
connectionFactory.setHost("5672");
connectionFactory.setUsername("jack");
connectionFactory.setPassword("123456");
connectionFactory.setVirtualHost("/");
connectionFactory.setPublisherConfirms(true); // publisher确认模式
connectionFactory.setPublisherReturns(true); // publisher没有路由返回
connectionFactory.setConnectionTimeout(6 * 1000); //ting.cai 1212 超时6s
return connectionFactory;
}
2 消费者
public class Receiver implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
System.out.println(" 消费者接收到消息:" + new String(message.getBody(),"utf-8"));
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);// 手动确认消息收到ack
}
}
@Bean
Receiver receiver(){
return new Receiver();
}
@Bean
SimpleMessageListenerContainer myListenerContainer(ConnectionFactory connectionFactory,
Receiver receiver) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("myQueue");
container.setMessageListener(receiver);
// NONE 和自动差不多,只不过broker认为consumer是不会发送任何ack
// MANUAL 手动 AUTO 自动确认,onMessage()方法抛出异常例外
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return container;
}
3 生产者
3.1 channel的缓存
@Bean
RabbitTemplate myTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
return template;
}
实际上是一个channel的缓存,默认有25个channel,发送消息时,会从缓存中取空闲的channel,底层再通过channel发送
注意:设置的确认回调方法会被template里面所有缓存channel所共有,所以必须考虑所有使用这个template发送消息业务是否兼容这个回调
所以我建议对于使用confirm回调,本业务的发送和确认回调监听应该使用使用connectionfactory重新创建一个template
myTemplate.setConfirmCallback((CorrelationData correlationData, boolean ack, String errorMsg) -> {
if(ack){
System.out.println("ack==> confirm:correlationData=" + correlationData.getId() + " ack= " + ack);
unAckMessageMap.remove(correlationData.getId());
}
}
无法投递到queue的回调也有同样channel缓存问题
myTemplate.setMandatory(true);// 强制投递,投递不到queue才会回调
myTemplate.setReturnCallback((Message message, int replyCode, String replyText,
String exchange, String routingKey)->{
});
3.2 申明broker的queue、exchange、binding
@Bean
public Queue myQueue(){
return new Queue("myQueue");
}
@Bean
DirectExchange myExchange() {
return new DirectExchange("myExchange");
}
@Bean
Binding myBinding(Queue myQueue, DirectExchange myExchange) {
return BindingBuilder.bind(myQueue).to(myExchange).with("myRoutingKey");
}
// AmqpAdmin会激活queue,binding,exchange,否则未激活状态
@Bean
public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory,
Queue myQueue,
DirectExchange myExchange,
Binding myBinding) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
// 如果队列不存在,可以自动创建一个
rabbitAdmin.declareQueue(myQueue);
rabbitAdmin.declareExchange(myExchange);
rabbitAdmin.declareBinding(myBinding);
return rabbitAdmin;
}
3.3 发送
String id = getId();
// 指定投递的exchage和路由键 myTemplate.convertAndSend("myExchange","myRoutingKey","hello the world {id = " + id + "}", new CorrelationData(id)); unAckMessageMap.put(id,"hello the world");