RabbitMQ
1.RabbitMQ基本知识点
1.1基本使用
直接使用不使用交换机,意思是使用的默认的交换机名称参数为:""
消费者
public class ExchangeConsumer { public static void main(String[] args) throws IOException, TimeoutException { //获取channel,可以看成提供者的getChannel Channel channel = consumer.getChannel(); //获取交换机 // channel.exchangeDeclare("myChange", BuiltinExchangeType.DIRECT); // 绑定队列 // channel.queueBind("HelloWorld", "myChange", "t1"); /* //发送 for (int i = 0; i < 10; i++) { String s = i+"弟弟大点掉"; channel.basicPublish("myChange", "t1", null, s.getBytes()); }*/ // 接受 channel.basicConsume("HelloWorld1", false, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(new String(body)); } }); } }
提供者
public class producer { public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException, IOException, TimeoutException { Channel channel = getChannel(); channel.queueDeclare("HelloWorld", true, false, false, null); //发送消息 for (int i = 0; i < 10; i++) { channel.basicPublish("", "HelloWorld", null, "嘿嘿连载".getBytes()); } //关闭连接 /* channel.close(); connection.close();*/ } public static Channel getChannel() throws IOException, TimeoutException { //获取工厂对象 ConnectionFactory factory=new ConnectionFactory(); //拿到连接 factory.setHost("47.111.236.242"); factory.setPort(5672); factory.setVirtualHost("/test"); factory.setUsername("demo"); factory.setPassword("demo"); Connection connection = factory.newConnection(); //获取channel return connection.createChannel(); } }
1.2RabbitMQ的四种交换机模式
所有交换机都对应一个
1.2.1直接交换机(Direct)
在Rabbit的java包中,有DirectExchange代表直接交换机
它通过routingkey来判断把消息发送给谁,如果没有routingkey就会报错,同时它除了表达方式可以和Topic通配交换机有一定的情况使用是相同,和其他的交换机的使用方法是一点不一样的.(路由key可以重复).
1.2.2扇形(广播)交换机(Fanout)
在Rabbit的spring整合包中,有FanoutExchange代表广播交换机
他是按照绑定情况,不分路由key的,只要进行绑定的队列都会进行发送
1.2.3通配符交换机(Topic)
在Rabbit的spring整合包中,有TopicExchange代表通配符交换机
它进行routingkey的匹配模式进行发送消息,如果绑定时设置的routingkey不符合通配符要求就不发送
注:#代表所有路径a.#代表以a.开头的所有a.c.d;
*代表单层路径a.*只能匹配a.b
//广播 Binding ss = BindingBuilder.bind(queue).to(new FanoutExchange("ss")); //适配器 Binding aa = BindingBuilder.bind(queue).to(new TopicExchange("aa")).with("bind.#"); //直接 BindingBuilder.bind(queue).to(Directexchange).with("bind"); //默认 Exchange aa1 = new DirectExchange("aa"); Binding bind = BindingBuilder.bind(queue).to(aa1).with("bind").noargs();
2.RabbitMQ整合spring使用
2.1环境配置
spring的环境依赖+spring整合RabbitMQ的依赖
<dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> <version>2.1.8.RELEASE</version> </dependency>
2.2关于RabbitMQ在spring配置文件中如何配置
消费者
<!--RabbitMQ的连接工厂必须注入--> <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}" virtual-host="${rabbitmq.virtual-host}"/> <!--监听器的配置,消费者必须配置监听器,这部是注册监听--> <!-- <bean id="springQueueListener" class="com.ljr.consumer.listener.DirectListener"/>--> <bean id="fanoutListener1" class="com.ljr.consumer.listener.FanoutListener" /> <bean id="fanoutListener2" class="com.ljr.consumer.listener.FanoutListener"/> <bean id="topicListenerStar" class="com.ljr.consumer.listener.TopicListener"/> <bean id="topicListenerWell" class="com.ljr.consumer.listener.TopicListener"/> <bean id="topicListenerWell2" class="com.ljr.consumer.listener.TopicListener"/> <!--RabbitMQ的监听器绑定,不绑定则无法监听--> <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true" acknowledge="none"> <!-- <rabbit:listener ref="springQueueListener" queue-names="spring_queue"/>--> <rabbit:listener ref="fanoutListener1" queue-names="spring_fanout_queue_1"/> <rabbit:listener ref="fanoutListener2" queue-names="spring_fanout_queue_2"/> <rabbit:listener ref="topicListenerStar" queue-names="spring_topic_queue_star"/> <rabbit:listener ref="topicListenerWell" queue-names="spring_topic_queue_well"/> <rabbit:listener ref="topicListenerWell2" queue-names="spring_topic_queue_well2"/> </rabbit:listener-container>
提供者
<!-- 定义rabbitmq connectionFactory 确认模式,提供者发送消息可以获得mq的反馈,是否接收成功(在restTelement.confirm会出现想要的方法) publisher-confirms="true" 回退模式 在发送给交换机的时候,发送失败才会实现的,有两种处理策略: 1.直接丢弃;2返回失败消息给发送方 publisher-return="true"--> <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}" virtual-host="${rabbitmq.virtual-host}" /> <!--定义管理交换机、队列的RabbitAdmin对象,只有注入这个对象,才能进行交换机和队列的管理 如: //创建交换机,无则创建有则跳过 rabbitAdmin.declareExchange(new FanoutExchange("test.exchange.fanout", true, false)); rabbitAdmin.declareExchange(new DirectExchange("test.exchange.direct", true, false)); rabbitAdmin.declareExchange(new TopicExchange("test.exchange.topic", true, false)); 没有这个类就无法进行管理创建,这里没有写名字是因为spring默认给他的名字为"rabbitAdmin" 创建之后就会默认使用,无需再次标明(随便起什么名字ID) --> <rabbit:admin connection-factory="connectionFactory"/> <!--定义持久化队列,不存在则自动创建;不绑定到交换机则绑定到默认交换机 默认交换机类型为direct,名字为:"",路由键为队列的名称 auto-delete="true"满足两个条件: 1:首先至少有一个消费者使用过这个队列 2:没有消费者使用这个队列 才会进行删除 --> <rabbit:queue id="spring_queue" name="spring_queue" auto-declare="true"/> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~广播;所有队列都能收到消息~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1" auto-declare="true"/> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2" auto-declare="true" /> <!--定义广播类型交换机;并绑定上述两个队列--> <rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange" auto-declare="true"> <rabbit:bindings> <rabbit:binding queue="spring_fanout_queue_1"/> <rabbit:binding queue="spring_fanout_queue_2"/> </rabbit:bindings> </rabbit:fanout-exchange> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~通配符;*匹配一个单词,#匹配多个单词 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star" auto-declare="true"/> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_topic_queue_well2" name="spring_topic_queue_well2" auto-declare="true"/> <rabbit:topic-exchange id="spring_topic_exchange" name="spring_topic_exchange" auto-declare="true"> <!--#匹配所有,*只能匹配一层*a*可以匹配带有一层的带a--> <rabbit:bindings> <rabbit:binding pattern="heima.*" queue="spring_topic_queue_star"/> <rabbit:binding pattern="heima.#" queue="spring_topic_queue_well"/> <rabbit:binding pattern="itcast.#" queue="spring_topic_queue_well2"/> </rabbit:bindings> </rabbit:topic-exchange> <!--定义rabbitTemplate对象操作可以在代码中方便发送消息--> <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
在消息被消费者接受时,MQ无法确认你获取到了消息是否正常处理,所以说我们在消费者接收消息之后需要告诉MQ消息是否正常处理,在连接的时候 在配置监听器容器的时候,加入 acknowledge="none/manual/auto" 自动确认/手动确认/根据异常类型确认.
如果是手动确认,我们可以重写或者实现MessageListener的子类.在其内部实现手动确认channel.basicAsk(driverTag,true);
2.3实战
在需要使用的地方依赖注入RabbitTelement,使用其方法方便我们的操作
如:
提供者
template.convertAndSend("spring_topic_exchange", "heima.a.b", "沃德吉尔英邦邦");
消费者
必须定义监听器,否则无法获取消息
监听器可以通过配置文件配置如上面的消费者配置文件
监听器必须实现接口RabbitListener,或者MessageListener的实现类
public class DirectListener implements MessageListener { @Override public void onMessage(Message message) { System.out.println(new String(message.getBody())); } }
通过Message的各种方法获取消息信息
3.RAbbitMQ整合SpringBoot
3.1.环境配置
导入springboot整合rabbitMq的包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit-test</artifactId> <scope>test</scope> </dependency>
可以使用@ImportResource导入配置文件
也可以通过配置类
@Configuration public class RabbitMQConfig { /* 定义直接交换机 */ @Bean("springbootExchange") public Exchange SpringbootExchange() { return new DirectExchange("springbootExchange"); } /* 定义队列 */ @Bean("springbootQueue") public Queue SpringbootQueue() { return new Queue("springbootQueue"); } /* 绑定交换机和队列 注意不同的交换机有不同的BindingBuilder的bind方法 */ @Bean public Binding bind(@Qualifier("springbootExchange")Exchange exchange,@Qualifier("springbootQueue")Queue queue) { /* //广播 Binding ss = BindingBuilder.bind(queue).to(new FanoutExchange("ss")); //适配器 Binding aa = BindingBuilder.bind(queue).to(new TopicExchange("aa")).with("bind.#"); //直接 BindingBuilder.bind(queue).to(exchange).with("bind"); //默认 Exchange aa1 = new DirectExchange("aa"); Binding bind = BindingBuilder.bind(queue).to(aa1).with("bind").noargs();*/ return BindingBuilder.bind(queue).to(exchange).with("bind").noargs(); } }
3.2实战
和spring没什么区别