概念
特点
安全,可靠,解耦合,异步,高吞吐,低延迟
MQ常用应用场景
异步通信,缓冲,解耦,冗余,扩展性,可恢复性,顺序保证,过载保护,数据流处理
一般处理方式(不使用MQ)
MQ消息处理方式
缓冲,解耦,异步通信,扩展性,可恢复性,顺序保证,过载保护
异构系统,解耦
数据流处理(kafka),日志处理
一般的MQ连接使用基础(Queue)
发送端
package com.study;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
//消息发送
public class Sender {
public static void main(String[] args) throws Exception {
//1. 获取连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnectionFactory.DEFAULT_USER,
ActiveMQConnectionFactory.DEFAULT_PASSWORD,
"tcp://localhost:61616"
);
//2. 获取一个向ActiveMQ的连接
Connection connection = connectionFactory.createConnection();
//3. 获取session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4. 找目的地,获取destination,消费端,也会从这个目的地取数据
Queue queue = session.createQueue("user");
//5.1 消息创建者
MessageProducer producer = session.createProducer(queue);
//consumer -> 消费者
//producer -> 创建者
//5.2 创建消息
for (int i = 0; i < 100; i++) {
TextMessage textMessage = session.createTextMessage("hi~" + i);
//5.3 向目的地写入数据
producer.send(textMessage);
Thread.sleep(1000);
}
//6. 关闭连接
connection.close();
System.out.println("System exit ...");
}
}
消费端
package com.study;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
//消息接收
public class Receiver {
public static void main(String[] args) throws Exception {
//1. 获取连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnectionFactory.DEFAULT_USER,
ActiveMQConnectionFactory.DEFAULT_PASSWORD,
"tcp://localhost:61616"
);
//2. 获取一个向ActiveMQ的连接
Connection connection = connectionFactory.createConnection();
connection.start();
//3.获取session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4. 找目的地,获取destination
Queue queue = session.createQueue("user");
//5.1 创建消费者
MessageConsumer consumer = session.createConsumer(queue);
while (true) {
TextMessage message = (TextMessage) consumer.receive();
System.out.println("message = " + message.getText());
}
}
}
同步
过程
监听器方式代码实现
package com.activemq;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.util.ArrayList;
import java.util.List;
public class Receiver {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnectionFactory.DEFAULT_USER,
ActiveMQConnectionFactory.DEFAULT_PASSWORD,
"tcp://localhost:61616"
);
List<String> list = new ArrayList<String>();
list.add(User.class.getPackage().getName());
connectionFactory.setTrustedPackages(list);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("user");
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(new MyListener());
}
}
class MyListener implements MessageListener {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
} else if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
try {
User user = (User) objectMessage.getObject();
System.out.println(user);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
确认机制
问题
选择器
分组
#发送端分组
MapMessage msg1 = session.createMapMessage();
msg1.setString("name", "qiqi");
msg1.setString("age", "18");
msg1.setStringProperty("name", "qiqi");
msg1.setIntProperty("age", 18);
MapMessage msg2 = session.createMapMessage();
msg2.setString("name", "lucy");
msg2.setString("age", "18");
msg2.setStringProperty("name", "lucy");
msg2.setIntProperty("age", 18);
MapMessage msg3 = session.createMapMessage();
msg3.setString("name", "qianqian");
msg3.setString("age", "17");
msg3.setStringProperty("name", "qianqian");
msg3.setIntProperty("age", 17);
#接收端分组
String selector1 = "age > 17";
String selector2 = "name = 'lucy'";
MessageConsumer consumer = session.createConsumer(queue,selector2);
独占消费者
Queue queue = session.createQueue("xxoo?consumer.exclusive=true");
还可以设置优先级
Queue queue = session.createQueue("xxoo?consumer.exclusive=true&consumer.priority=10");
同步异步
producer和broker,consumer和broker同步异步
connectionFactory.setSendAcksAsync(true);
ActiveMQConnection activeMQConnection = (ActiveMQConnection) connection;
activeMQConnection.setUseAsyncSend(true);
开启事务 | 关闭事务 | |
---|---|---|
持久化 | 异步 | 同步 |
非持久化 | 异步 | 异步 |
producer和consumer同步(QueueRequestor)
request方法源码
public Message request(Message message) throws JMSException {
message.setJMSReplyTo(getTemporaryQueue());
getSender().send(message);
return getReceiver().receive();
}
同步消息失去性能,牺牲了大部分的性能, QueueRequestor极强的一致性
journal持久化方式
通信
textMessage.setJMSReplyTo(new ActiveMQQueue("reply"));
集成springboot使用
application.properties
server.port=8080
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=5
spring.activemq.pool.idle-timeout=0
spring.activemq.packages.trust-all=true
spring.jms.pub-sub-domain=true
ActiveMQConfig
package com.activemq.springboot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import javax.jms.ConnectionFactory;
@Configuration
@EnableJms
public class ActiveMQConfig {
//pub/sub
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactoryTopic(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setPubSubDomain(true);
bean.setConnectionFactory(connectionFactory);
return bean;
}
//queue
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactoryQueue(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setConnectionFactory(connectionFactory);
return bean;
}
}
SenderServer
package com.activemq.springboot.service;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import javax.jms.*;
import java.util.ArrayList;
import java.util.List;
@Service
public class SenderServer {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Autowired
private JmsTemplate jmsTemplate;
public void send(String destination, String msg) {
List<String> list = new ArrayList<>();
list.add("malaoshi");
list.add("lian");
list.add("zhanglaoshi");
jmsMessagingTemplate.convertAndSend(destination, list);
}
public void send2(String destination, String msg) {
ConnectionFactory connectionFactory = jmsTemplate.getConnectionFactory();
Connection connection = null;
try {
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
} catch (JMSException e) {
e.printStackTrace();
}
jmsTemplate.send(destination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage("xxoo");
textMessage.setStringProperty("hehe", "enen");
return textMessage;
}
});
}
public void send3(String destination, String msg) {
List<String> list = new ArrayList<>();
list.add("malaoshi");
list.add("lian");
list.add("zhanglaoshi");
jmsMessagingTemplate.convertAndSend(new ActiveMQQueue(destination), list);
}
}
ReceiverServer
package com.activemq.springboot.service;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;
@Service
public class ReceiverServer {
@JmsListener(destination = "springboot", containerFactory = "jmsListenerContainerFactoryTopic")
public void receiver(String msg) {
System.out.println("收到消息: " + msg);
}
}
MainController
package com.activemq.springboot.controller;
import com.activemq.springboot.service.SenderServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MainController {
@Autowired
SenderServer senderServer;
@RequestMapping("/send")
public String send() {
senderServer.send3("springboot", "hello~~");
return "ok";
}
}
消息之间的关联会话
多个消息一个CID,就可以产生分组了
推拉消息
异步的发消息
异步的消费消息
慢消费问题
Request/Response模型实现
1.临时队列实现
2.通过CorrelationID来实现
3.通过QueueRequestor同步阻塞来实现
高可用
通过共用数据源来实现