springboot整合ActiveMQ(点对点和发布订阅)
ActiveMQ是什么,为什么使用MQ
是基于 Java 中的 JMS 消息服务规范实现的一个消息中间件。
1.系统解耦
采用中间件之后,就可以完美解决上述中因为耦合可能导致的问题。系统 A 不用去
关心下层服务调用方的问题。
2. 异步调用
当一个请求处理需要经过 3 个系统的时候,A 和 B 系统处理时间 3ms 时间,这个是非
常快的,但是 C 系统可能需要 30s 才能处理完。这样整个业务处理时间因为 C 系统导
致非常慢。
比如我们在美团或者饿了吗下单,那么在下单的时候,后台需要通过后台处理:订单支
付->账户扣款->创建订单->通知商家准备菜品->安排骑手
这个时候我们对于扣款和创建订单来讲对于时效性要求强,处理效率也比较高。对于通
知商家准备菜品和安排骑手来讲时效性的要求不是很高,处理时间也可能会稍长。这个
时候就可以使用 mq 进行异步处理,先处理完前面的业务,然后反馈给用户,之后再通
过 mq 处理通知商家准备菜品和安排骑手
3.流量削峰
大部分时候,每秒几百请求,一台机器就足够了,但是为了抗那每天瞬时的高峰,硬是
部署了 10 台机器,每天就那半个小时有用,别的时候都是浪费资源的。
但是如果你就部署一台机器,那会导致瞬时高峰时,一下子压垮你的系统,因为绝对无
法抗住每秒几千的请求高峰。此时我们就可以用 MQ 中间件来进行流量削峰
所有机器前面部署一层 MQ,平时每秒几百请求大家都可以轻松接收消息。一旦到了瞬
时高峰期,一下涌入每秒几千的请求,就可以积压在 MQ 里面,然后那一台机器慢慢
的处理和消费。等高峰期过了,再消费一段时间,MQ 里积压的数据就消费完毕了。
转自王炬
知道了为什么要使用消息中间件,下面直接上代码了。
1:首先我们先打开ActiveMQ
打开网站输入:http://127.0.0.1:8161/ 出现以下画面,则启动成功
代码我直接贴出(点对点和发布订阅)的整合模式
Queue与Topic 消息传递模式区别
1)点对点(point-to-point,简称PTP)Queue消息传递模型:
通过该消息传递模型,一个应用程序(即消息生产者)可以向另外一个应用程序(即消息消费者)发送消息。在此传递模型中,消息目的地类型是队列(即Destination接口实现类实例由Session接口实现类实例通过调用其createQueue方法并传入队列名称而创建)。消息首先被传送至消息服务器端特定的队列中,然后从此对列中将消息传送至对此队列进行监听的某个消费者。同一个队列可以关联多个消息生产者和消息消费者,但一条消息仅能传递给一个消息消费者。如果多个消息消费者正在监听队列上的消息,,JMS消息服务器将根据“先来者优先”的原则确定由哪个消息消费者接收下一条消息。如果没有消息消费者在监听队列,消息将保留在队列中,直至消息消费者连接到队列为止。这种消息传递模型是传统意义上的懒模型或轮询模型。在此模型中,消息不是自动推动给消息消费者的,而是要由消息消费者从队列中请求获得。
2)发布/订阅(publish/subscribe,简称pub/sub)Topic消息传递模型:
通过该消息传递模型,应用程序能够将一条消息发送给多个消息消费者。在此传送模型中,消息目的地类型是主题(即Destination接口实现类实例由Session接口实现类实例通过调用其createTopic方法并传入主题名称而创建)。消息首先由消息生产者发布至消息服务器中特定的主题中,然后由消息服务器将消息传送至所有已订阅此主题的消费者。主题目标也支持长期订阅。长期订阅表示消费者已注册了主题目标,但在消息到达目标时该消费者可以处于非活动状态。当消费者再次处于活动状态时,将会接收该消息。如果消费者均没有注册某个主题目标,该主题只保留注册了长期订阅的非活动消费者的消息。与PTP消息传递模型不同,pub/sub消息传递模型允许多个主题订阅者接收同一条消息。JMS一直保留消息,直至所有主题订阅者都接收到消息为止。pub/sub消息传递模型基本上是一个推模型。在该模型中,消息会自动广播,消息消费者无须通过主动请求或轮询主题的方法来获得新的消息。
转自我傲故我狂
项目目录
导入包
<!--整合消息队列ActiveMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!--若配置线程池则加入-->
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
Controller(生产者)
order点对点 topic 发布订阅
package cn.hp.springboot_07.controller;
import cn.hp.springboot_07.service.ProducerService;
import cn.hp.springboot_07.utils.JsonData;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Destination;
@RestController
@RequestMapping("/api")
public class OderController {
@Autowired
private ProducerService producerService;
@RequestMapping("/order")
public Object order(String msg) {
Destination destination = new ActiveMQQueue("tlog.quetue");
producerService.sendMag(destination,msg);
return JsonData.buildSuccess();
}
@RequestMapping("/topic")
public Object topic(String msg){
producerService.publicMsg(msg);
return JsonData.buildSuccess();
}
}
jsm(消费者)
NewComsumer
注意@Component交给spring容器管理
package cn.hp.springboot_07.jsm;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
/**
* 订阅模式的 消费者,可以支持多个消费者消费
*/
@Component
public class NewComsumer {
@JmsListener(destination = "news.topic",containerFactory = "jmsListenerContainerTopic")
public void comsumer(String msg){
System.out.println("消费者1接收的报文"+msg);
}
@JmsListener(destination = "news.topic",containerFactory = "jmsListenerContainerTopic")
public void comsumer2(String msg){
System.out.println("消费者2接收的报文"+msg);
}
@JmsListener(destination = "news.topic",containerFactory = "jmsListenerContainerTopic")
public void comsumer3(String msg){
System.out.println("消费者3接收的报文"+msg);
}
}
OrderConsumer
package cn.hp.springboot_07.jsm;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class OrderConsumer {
/**
* JmsListener消息监听(时时监听,只有发现有消息发送过来,会like消费)
*/
@JmsListener(destination = "tlog.quetue")
public void consumerOrder(String msg){
System.out.println("接收的报文"+msg);
}
}
ProducerService
package cn.hp.springboot_07.service;
import javax.jms.Destination;
/**
* 消息的产生或者提供者 服务
*/
public interface ProducerService {
/**
* 发送消息,destination 消息接收者(他也是一个队列)
* @param destination
* @param msg
*/
public void sendMag(Destination destination, String msg);
/**
* 发送默认消息,由默认消息队列接收
* @param msg
*/
public void sendDefaultMsg(String msg);
/**
* 订阅模式
* @param msg
*/
void publicMsg(String msg);
}
ProducerServiceImp
package cn.hp.springboot_07.service.imp;
import cn.hp.springboot_07.service.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;
import javax.jms.Queue;
import javax.jms.Topic;
@Service
public class ProducerServiceImp implements ProducerService {
@Autowired
private Queue queue;
@Autowired
private JmsMessagingTemplate template; //jsm消息模板,此处用于消息发送
@Override
public void sendMag(javax.jms.Destination destination, String msg) {
template.convertAndSend(destination,msg);
}
@Override
public void sendDefaultMsg(String msg) {
template.convertAndSend(queue,msg);
}
@Autowired
private Topic topic;//注入topic主题(其实就是一个队列)
@Override
public void publicMsg(String msg) {
template.convertAndSend(topic,msg);
}
}
Uitl(JsonData)
链接
增加一下访问O(∩_∩)O哈哈~
Springboot07Application
package cn.hp.springboot_07;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import javax.jms.ConnectionFactory;
import javax.jms.Queue;
import javax.jms.Topic;
@SpringBootApplication
@EnableJms //支持jms
public class Springboot07Application {
//在当前类引入一个队列
/**
* @Bean是将当前方法注入到spring容器,当前方法返回对象作为一个bean对象使用
* @Commpoment 是将当前类注入到spring容器,将当前类的对象作为1个bean对象使用
* @return
*/
@Bean
public Queue queue(){
return new ActiveMQQueue("tlog.quetue");
}
/**
* 发布订阅模式
* @param
*/
@Bean
public Topic topic(){
return new ActiveMQTopic("news.topic");
}
/**
* 配置支持 点对点 和 发布订阅
* @param activeMQConnectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ConnectionFactory activeMQConnectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setPubSubDomain(true);
bean.setConnectionFactory(activeMQConnectionFactory);
return bean;
}
public static void main(String[] args) {
SpringApplication.run(Springboot07Application.class, args);
}
}
application.properties
最后一个,(spring.jms.pub-sub-domain)
如果单单开启点对点则不需要
如果要开启订阅模式,则开启
如果要点对点,订阅模式都要开启则不需要
#整合jms测试,安装在别的机器,防火墙和端口号记得开放,若防火墙已关闭,此处可忽略
spring.activemq.broker-url=tcp://127.0.0.1:61616
#集群配置
#spring.activemq.broker-url=failover:(tcp://localhost:61616,tcp://localhost:61617)
spring.activemq.user=admin
spring.activemq.password=admin
#使用连接池
spring.activemq.pool.enabled=true
#连接池最大连接数
spring.activemq.pool.max-connections=100
#默认点对点,开启订阅模式
#spring.jms.pub-sub-domain=true