消息中间件的定义:
没有标准定义,一般认为,采用消息传送机制/****消息队列** **的中间件技术,进行数据交流,用在分布式系统的集成
为什么要用消息中间件?
解决分布式系统之间消息的传递。
电商场景:用户下单减库存,调用物流系统,系统扩充后服务化和业务拆分。系统交互,y一般用RPC(远程过程调用)。如果系统扩充到有几十个接口,消息中间件来解决问题。
和RPC有何区别?
使用区分标准:1、系统之间的依赖程度 2、量(业务量,数据量,访问量)
消息中间件有些什么使用场景?
1、 异步处理
用户注册(50ms),还需发送邮件(50ms)和短信(50ms)
串行:(150ms)用户注册—》发送邮件----》发送短信
并行(100ms):用户注册—》发送邮件
|----》发送短信
消息中间件(56ms):
用户注册(50ms)—》(6ms)消息中间件《-----发送邮件
《-----发送短信
2、 应用的解耦
订单系统---》库存系统(强耦合)
消息中间件:订单系统---》消息中间件《----库存系统(解耦)
3、 流量的削峰
用户请求-----》秒杀应用
应用的前端加入消息队列
用户请求-----》消息队列《----秒杀应用
4、 日志处理
错误日志---》消息队列《----日志处理
用户行为日志--》消息队列(kafka)《-----日志的存储或流式处理
5、纯粹的消息通信
常见消息中间件比较
kafka****和RabbitMQ****的比较
1、 RabbitMq比kafka成熟,在可用性上,稳定性上,可靠性上,RabbitMq超过kafka
2、 Kafka设计的初衷就是处理日志的,可以看做是一个日志系统,针对性很强,所以它并没有具备一个成熟MQ应该具备的特性
3、 Kafka的性能(吞吐量、tps)比RabbitMq要强
什么是JMS规范
本质是API,Java平台消息中间件的规范,java应用程序之间进行消息交换。并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
JMS对象模型包含如下几个要素:
1)连接工厂:创建一个JMs连接
2)JMS连接:客户端和服务器之间的一个连接。
3)JMS会话:客户和服务器会话的状态,建立在连接之上的
4)JMS目的:消息队列
5)JMS生产者:消息的生成
6)JMS消费者:接收消息
7)Broker:消息中间件的实例(ActiveMq)
JMS规范中的点对点模式:
队列,一个消息只有一个消费者(即使有多个接受者监听队列),消费者是要向队列应答成功
JMS规范中的主题模式(发布订阅):
发布到Topic的消息会被当前主题所有的订阅者消费
JMS规范中的消息类型
TextMessage,MapMessage,ObjectMessage,BytesMessage,StreamMessage
代码:不配置Spring
pom.xml
org.apache.activemq
activemq-all
5.8.0
Producer
public class JmsProducer {
//默认连接用户名
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
//默认连接密码
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
//默认连接地址
private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL;
//发送的消息数量
private static final int SENDNUM = 10;
public static void main(String[] args) {
ConnectionFactory connectionFactory;
Connection connection = null;
Session session;
Destination destination;
MessageProducer messageProducer;
connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEURL);
try {
connection = connectionFactory.createConnection();
connection.start();
/*
createSession参数取值
* 1、为true表示启用事务
* 2、消息的确认模式
* AUTO_ACKNOWLEDGE 自动签收
* CLIENT_ACKNOWLEDGE 客户端自行调用acknowledge方法签收
* DUPS_OK_ACKNOWLEDGE 不是必须签收,消费可能会重复发送
* 在第二次重新传送消息的时候,消息
头的JmsDelivered会被置为true标示当前消息已经传送过一次,
客户端需要进行消息的重复处理控制。
* */
session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("HelloWAM");
messageProducer = session.createProducer(destination);
for(int i=0;i
启动生产者后台发送10条消息到队列
Consumer
public class JmsConsumer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;//默认连接用户名
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码
private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL;//默认连接地址
public static void main(String[] args) {
ConnectionFactory connectionFactory;//连接工厂
Connection connection = null;//连接
Session session;//会话 接受或者发送消息的线程
Destination destination;//消息的目的地
MessageConsumer messageConsumer;//消息的消费者
//实例化连接工厂
connectionFactory = new ActiveMQConnectionFactory(JmsConsumer.USERNAME,
JmsConsumer.PASSWORD, JmsConsumer.BROKEURL);
try {
//通过连接工厂获取连接
connection = connectionFactory.createConnection();
//启动连接
connection.start();
//创建session
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建一个连接HelloWorld的消息队列
destination = session.createQueue("HelloWAM");
//创建消息消费者
messageConsumer = session.createConsumer(destination);
//读取消息
while(true){
TextMessage textMessage = (TextMessage)messageConsumer.receive(10000);
if(textMessage != null){
System.out.println("Accept msg : "+textMessage.getText());
}else{
break;
}
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
启动消费者
集成Spring,生产者部分
pom.xml
org.apache.activemq
activemq-all
5.8.0
org.springframework
spring-jms
4.3.11.RELEASE
Spring配置文件
QueueSender
@Component("queueSender")
public class QueueSender {
@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsTemplate;
@Autowired
private GetResponse getResponse;
public void send(String queueName,final String message){
jmsTemplate.send(queueName, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
Message msg = session.createTextMessage(message);
return msg;
}
});
}
}
TopicSender
@Component("topicSender")
public class TopicSender {
@Autowired
@Qualifier("jmsTopicTemplate")
private JmsTemplate jmsTemplate;
public void send(String queueName,final String message){
jmsTemplate.send(queueName, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
Message msg = session.createTextMessage(message);
return msg;
}
});
}
}
消费者部分
配置文件
QueueReceiver1
@Component
public class QueueReceiver1 implements MessageListener {
public void onMessage(Message message) {
try {
String textMsg = ((TextMessage)message).getText();
System.out.println("QueueReceiver1 accept msg : "+textMsg);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
QueueReceiver2
@Component
public class QueueReceiver2 implements MessageListener {
public void onMessage(Message message) {
try {
String textMsg = ((TextMessage)message).getText();
System.out.println("QueueReceiver2 accept msg : "+textMsg);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
TopicReceiver1
@Component
public class TopicReceiver1 implements MessageListener {
public void onMessage(Message message) {
try {
String textMsg = ((TextMessage)message).getText();
System.out.println("TopicReceiver1 accept msg : "+textMsg);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
TopicReceiver2
@Component
public class TopicReceiver2 implements MessageListener {
public void onMessage(Message message) {
try {
String textMsg = ((TextMessage)message).getText();
System.out.println("TopicReceiver2 accept msg : "+textMsg);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
启动Producer,发送Queue消息,启动Consumer,可看到点对点模式,有两个消费者,一条消息,只有一个消费者能接收到消息,是轮询方式。
主题订阅模式,可看到有两个消费者,一条消息,两个消费者都能接收到消息。