java使用rabbitmq的基本操作在前面两篇文章中已经讲过了,实际项目中,使用ssm框架整合rabbitmq比较常见,但对于新手来说,个人觉得spring在整合rabbitmq时候,xml的配置文件里很容易让人抓狂,但只要配置好了,基本上不需要做过多的改动
rabbitmq在实际使用中,主要的业务场景还是在分布式项目中,不同的业务处理完毕,需要异步的发送消息进行通讯的情况下,可以考虑使用rabbitmq或其他的消息中间件,这里,将演示springboot整合rabbitmq进行消息的通讯,为模拟分布式环境,直接创建两个maven工程
项目名称可以自己定义,一个工程模拟生产者,一个模拟消费者,
工程启动前,先将rabbitmq的服务启动起来,并根据需求提前创建工程中需要的用户,exchange,vHost,queue等
为使用方便,我已经提前将相关的配置信息在管控台中配置完毕;
首先看生产者端代码,这里为演示效果,将模拟几种不同的使用方式,首先看pom依赖jar包,
org.springframework.boot
spring-boot-starter-parent
2.0.1.RELEASE
UTF-8
UTF-8
1.8
4.1.0-incubating
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-activemq
org.apache.activemq
activemq-pool
org.apache.rocketmq
rocketmq-client
${rocketmq.version}
org.apache.rocketmq
rocketmq-common
${rocketmq.version}
org.apache.rocketmq
rocketmq-client
4.1.0-incubating
org.projectlombok
lombok
provided
com.google.code.gson
gson
2.8.5
org.springframework.boot
spring-boot-starter-amqp
junit
junit
4.12
接下来是配置文件,连接rabbitmq的配置信息在application.properties中进行配置:
server.port=8084
spring.application.name=rabbitmq-sender
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=acong
spring.rabbitmq.password=acong
spring.rabbitmq.virtual-host=/test
spring.rabbitmq.publisher-confirms=true
bean包下存放的是对象类文件;
config包下存放的是初始化连接rabbitmq的配置文件,会在项目启动的时候进行全局加载,比如,消费者要绑定的exchange,相关的队列,消息确认相关配置等;
controller包模拟前端发送消息,作为测试的入口文件;
接下来看具体的代码,首先看config下的配置文件:
@Component
public class TopicConfig {
final static String queueName = "hello";
@Bean
public Queue helloQueue() {
return new Queue("hello");
}
@Bean
public Queue userQueue() {
return new Queue("user");
}
// ===============以下是验证topic Exchange的队列==========
@Bean
public Queue queueMessage() {
return new Queue("topic.message");
}
@Bean
public Queue queueMessages() {
return new Queue("topic.messages");
}
// ===============以上是验证topic Exchange的队列==========
// ===============以下是验证Fanout Exchange的队列==========
@Bean
public Queue AMessage() {
return new Queue("fanout.A");
}
@Bean
public Queue BMessage() {
return new Queue("fanout.B");
}
@Bean
public Queue CMessage() {
return new Queue("fanout.C");
}
// ===============以上是验证Fanout Exchange的队列==========
@Bean
TopicExchange exchange() {
return new TopicExchange("ttoo");
}
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
}
/**
* 将队列topic.message与exchange绑定,binding_key为topic.message,就是完全匹配
*
* @param queueMessage
* @param exchange
* @return
*/
@Bean
Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
/**
* 将队列topic.messages与exchange绑定,binding_key为topic.#,模糊匹配
*
* @param queueMessage
* @param exchange
* @return
*/
@Bean
Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
@Bean
Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(AMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(BMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(CMessage).to(fanoutExchange);
}
}
在这个配置文件中,初始化定义了项目中可能要用到的队列名称,exchange绑定的队列名,以及定义的路由规则,这些写法属于固定的模式和套路,只是在springboot中,在原本的声明式的写法下进行了进一步的封装,属于换汤不换药,这个里面的配置写好了后面只需拿来即可使用,
配置完毕,接下来编写生产者端的代码,这里演示一种使用方式,即topic的使用方式,其他的类似,参考即可,
这两处的代码的意思是,为某个exchange绑定两个不同的queue,不同的是这两个队列订阅的消息策略有所不同,queueMessage匹配的topic.message开头的消息,而queueMessages匹配的以topic开头的所有消息,一会儿在消费端可以看出效果;
接下来是具体发送消息的代码;
@Component
public class TopicSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String msg1 = "我是主题发送的消息1 --->>>> I am topic.mesaage msg======";
System.out.println("sender1 : " + msg1);
this.rabbitTemplate.convertAndSend("exchange", "topic.message", msg1);
String msg2 = "我是主题发送的消息2 --->>>> I am topic.mesaages msg########";
System.out.println("sender2 : " + msg2);
this.rabbitTemplate.convertAndSend("exchange", "topic.messages",msg2);
}
}
注意导包的时候不要导错了;
接下来编写测试代码,在TopicSendController写一段测试的发送的消息代码,很简单,发送成功返回success,而且控制台也会打印出来,
@Controller
@RequestMapping(“/topic”)
public class TopicSendController {
@Autowired
private TopicSender topicSender;
@ResponseBody
@RequestMapping("/sendTopicMsg")
public String sendTopicMsg(){
topicSender.send();
return "topic send success";
}
}
接下来看消费者端的代码,消费端pom文件不变,application.properites的配置文件基本一致,
server.port=8085
spring.application.name=rabbitmq-consumer
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=acong
spring.rabbitmq.password=acong
spring.rabbitmq.virtual-host=/test
主要看接收消息的代码,消费者一段不需要做其他配置,在excehange下,只需要把要监听的队列名称写正确即可,因为在生产者一段,项目启动的时候,对应的exchange以及与之绑定的queue已经生效了,所以消费者一段不需再做配置,如果单独测试rabbimq的时候,是需要声明式配置的,
这里定义了两个消费者,模拟不同的路由键接收到的消息,
@Component
@RabbitListener(queues = “topic.message”)
public class TopicMessageReceiver {
@RabbitHandler
public void process(String msg) {
System.out.println("topicMessageReceiver 接收到了消息 : " +msg);
}
}
@Component
@RabbitListener(queues = “topic.messages”)
public class TopicMessageReceiver2 {
@RabbitHandler
public void process(String msg) {
System.out.println("topicMessageReceiver2 我能收到所有匹配的消息 ---- 接收到了消息 : " +msg);
}
}
需要注意,这里的注解写法不要随便修改,否则会报奇葩的错误,因为springboot底层已经对此作了进一步的封装,只需要拿来用即可,比如此处的:
@RabbitListener(queues = “topic.messages”)这个注解配合@RabbitHandler其实和单独使用rabbitmq时候,那个handlerDelivery的监听方法的效果是一样的,一旦生产者发送了消息,就能收到;
接下来,首先启动消费者端APP,
启动完毕,消费者监听程序生效,
再启动生产者APP,
接下来,在浏览器输入:
http://localhost:8084/topic/sendTopicMsg
可以看到,消费者端成功接收到了消息,同时可以验证topic模式下,通过在exchange中定义不同的queue的消息匹配策略,接收到的消息是不一样的,第一个消费者由于匹配的消息格式是:topic.message精准匹配,第二个是topic.#即模糊匹配,所以第一个消费者接收了一个消息,第二个消费者接收到了两条消息;
其他模式下,稍作修改即可,至此,springboot整合rabbitmq到此基本完毕,不足之处,敬请见谅,提出宝贵意见。