一、activeMQ數據庫持久化配置
ActiveMQ持久化的三種方式,我們採用數據庫的方式來進行持久化。
(1) Memory 消息存儲-基於內存的消息存儲。
(2) 基於日誌消息存儲方式,KahaDB是ActiveMQ的默認日誌存儲方式,它提供了容量的提升和恢復
能力。
(3) 基於JDBC的消息存儲方式-數據存儲於數據庫(例如:MySQL)中。
首先我們先來配置activeMQ
在conf文件夾裏的activeMQ.xml中增加一個jdbc的bean
<bean id="activemq-db" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
然後還是同一個文件,找到<persistenceAdapter>標籤修改:註釋掉原來的kahaDB方式持久化。
<persistenceAdapter>
<!-- <kahaDB directory="${activemq.base}/data/kahadb"/> -->
<!--createTablesOnStartup 啓動是否創建表 第一次爲true 後續爲false-->
<jdbcPersistenceAdapter dataSource="#activemq-db" createTablesOnStartup="true" />
</persistenceAdapter>
接着需要將一些jar包放在lib目錄裏。因爲我們用的是連接池和mysql,所以要導入四個jar包
配置好的MQ下載地址:https://download.csdn.net/download/qq_39404258/12561459
如果啓動失敗,報下面這樣的錯,說明你的mysql和mysql連接的jar包不匹配:
Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'OPTION SQL_SELECT_LIMIT=DEFAULT' at line 1
我用的mysql是5.6,用的mysql-connector是5.0.8,出現了這樣的錯,將mysql-connector改成了5.1.21就正常運行了。版本以自己的實際爲主。
二、ActiveMQ的兩種模型
點對點模型 queue
每個消息只有一個消費者( Consumer)(即一旦被消費,消息就不再在消息隊列中);
發送者和接收者之間在時間上沒有依賴性,也就是說當發送者發送了消息之後,不管接收者有沒有
正在運行,它不會影響到消息被髮送到隊列;
接收者在成功接收消息之後需向隊列應答成功。
發佈/訂閱模型 topic
每個消息可以有多個消費者;
發佈者和訂閱者之間有時間上的依賴性(先訂閱主題,再來發送消息)。
訂閱者必須保持運行的狀態,才能接受發佈者發佈的消息
使用jms原生消息進行示例:
生產者:
public class ProducerJMS {
public static String TCP_PATH="tcp://127.0.0.1:61616";
public static void main(String[] args) {
try {
//1.創建連接工廠
ConnectionFactory factory = new ActiveMQConnectionFactory();
//2.創建連接
Connection connection=factory.createConnection();
//3.打開連接
connection.start();
//4.創建session param1=事務是否開啓 param2=消息確認機制 如果開啓事務,第二個參數無用,且需要一個提交事務的操作
Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
//5.創建消息隊列
Topic topic =session.createTopic("q2");
Queue queue=session.createQueue("q1");
MessageProducer producer1=session.createProducer(topic);
//6.創建生產者
MessageProducer producer=session.createProducer(queue);
//7.創建消息
TextMessage textMessage=session.createTextMessage("new");
TextMessage textMessage1=session.createTextMessage("new1");
TextMessage textMessage2=session.createTextMessage("new2");
TextMessage top1=session.createTextMessage("top");
TextMessage top2=session.createTextMessage("top1");
TextMessage top3=session.createTextMessage("top2");
//8.發送消息到消息隊列
producer.send(textMessage);
producer.send(textMessage1);
producer.send(textMessage2);
producer1.send(top2);
producer1.send(top3);
producer1.send(top1);
//9.關閉連接
session.close();
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
消費者:
public class ConsumerJMS {
public static String URL_PATH="tcp://127.0.0.1:61616";
public static void main(String[] args) {
try{
//1.創建連接工廠
ConnectionFactory factory = new ActiveMQConnectionFactory(URL_PATH);
//2.創建連接
Connection connection = factory.createConnection();
//3.打開連接
connection.start();
//4.創建會話
Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
//5.創建目標地址(通道)
Queue queue =session.createQueue("q1");
Topic topic = session .createTopic("q2");
//6.創建消費者
MessageConsumer consumer1=session.createConsumer(topic);
MessageConsumer consumer=session.createConsumer(queue);
consumer1.setMessageListener(new MessageListener() {
@Override
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 {
System.out.println("類型錯誤!");
}
}
});
//7.接收消息,因爲在一直監聽,當有新消息來時,獲取,所以連接不能關
consumer.setMessageListener(new MessageListener() {
@Override
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 {
System.out.println("類型錯誤!");
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
啓動兩個消費者,然後啓動生產者,結果:
通過結果發現,queue的消息隨機分配給了兩個消費者,但topic的消息同時發給了他們兩個。
接着先啓動生產者,再啓動消費者,發現只收到了queue裏的消息。
三、在springboot中簡單使用
yml配置:
server:
port: 9081
spring:
activemq:
broker-url: tcp://127.0.0.1:61616
user: admin
password: admin
packages:
trust-all: true #信任包
jms:
pub-sub-domain: false #false點對點 true訂閱
template:
delivery-mode: persistent #持久化
activemq:
name: spring_queue
maven依賴:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
五種消息的使用實例:
生產者:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes= ProducerApplication.class)
public class Producer {
@Value("${activemq.name}")
private String messageName;
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Autowired
private JmsTemplate jmsTemplate;
@Test
public void ptpSend() {
jmsMessagingTemplate.convertAndSend("spring_queue", "new message");
}
@Test
public void ptpSendTextMessage() {
jmsTemplate.send(messageName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("testMessage");
}
});
}
@Test
public void ptpSendMapMessage() {
jmsTemplate.send(messageName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
MapMessage mapMessage =session.createMapMessage();
mapMessage.setString("name","zz");
mapMessage.setInt("age",1);
return mapMessage;
}
});
}
@Test
public void ptpSendUserMessage() {
jmsTemplate.send(messageName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
User user= new User("zhangsan",11);
return session.createObjectMessage(user);
}
});
}
@Test
public void ptpSendByteMessage() {
jmsTemplate.send(messageName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
File file =new File("D:\\img\\30.png");
BytesMessage bytesMessage = session.createBytesMessage();
try {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[(int)file.length()];
//將Stream裏的內容輸入到bytes裏
in.read(bytes);
bytesMessage.writeBytes(bytes);
} catch (Exception e) {
e.printStackTrace();
}
return bytesMessage;
}
});
}
@Test
public void ptpSendStreamMessage() {
jmsTemplate.send(messageName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
StreamMessage streamMessage = session.createStreamMessage();
streamMessage.writeDouble(2.2);
streamMessage.writeString("Stream");
return streamMessage;
}
});
}
}
消費者:
@Component
public class Consumer {
@JmsListener(destination = "${activemq.name}")
public void reveiced(Message message){
if (message instanceof TextMessage){
TextMessage textMessage=(TextMessage) message;
try {
System.out.println("接收消息:"+textMessage.getText());
} catch (Exception e) {
e.printStackTrace();
}
}else if (message instanceof MapMessage){
MapMessage mapMessage=(MapMessage) message;
try {
System.out.println("接收Map消息:"+mapMessage.getString("name")+","+mapMessage.getString("age"));
} catch (Exception e) {
e.printStackTrace();
}
}
else if (message instanceof ObjectMessage){
ObjectMessage objectMessage=(ObjectMessage) message;
try {
User user = (User) objectMessage.getObject();
System.out.println("接收Object消息:"+user.getName()+","+user.getAge());
} catch (Exception e) {
e.printStackTrace();
}
}
else if (message instanceof BytesMessage){
BytesMessage bytesMessage=(BytesMessage) message;
try {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\img1\\1.png");
byte[] bytes = new byte[(int)bytesMessage.getBodyLength()];
bytesMessage.readBytes(bytes);
fileOutputStream.write(bytes);
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
else if (message instanceof StreamMessage){
StreamMessage streamMessage=(StreamMessage) message;
try {
System.out.println("接收Stream消息:"+streamMessage.readDouble());
System.out.println("接收Stream消息:"+streamMessage.readString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}