今天整理一下Activemq消息持久化到mysql数据库的实现。
1.首先,修改Activemqconf目录下的activemq.xml文件,最好先备份一下。
把以下代码注释或删掉:
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
替换成以下代码:
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#derby-ds"/>
</persistenceAdapter>
在borker节点外添加以下代码:
<bean id="derby-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
其中,bean的id应与datasource是一样的。
最终文件配置:
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- START SNIPPET: example -->
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
<!-- Allows us to use system properties as variables in this configuration file -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>file:${activemq.conf}/credentials.properties</value>
</property>
</bean>
<!-- Allows accessing the server log -->
<bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
lazy-init="false" scope="singleton"
init-method="start" destroy-method="stop">
</bean>
<!--
The <broker> element is used to configure the ActiveMQ broker.
-->
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" >
<!-- The constantPendingMessageLimitStrategy is used to prevent
slow topic consumers to block producers and affect other consumers
by limiting the number of messages that are retained
For more information, see:
http://activemq.apache.org/slow-consumer-handling.html
-->
<pendingMessageLimitStrategy>
<constantPendingMessageLimitStrategy limit="1000"/>
</pendingMessageLimitStrategy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
<!--
The managementContext is used to configure how ActiveMQ is exposed in
JMX. By default, ActiveMQ uses the MBean server that is started by
the JVM. For more information, see:
http://activemq.apache.org/jmx.html
-->
<managementContext>
<managementContext createConnector="false"/>
</managementContext>
<!--
Configure message persistence for the broker. The default persistence
mechanism is the KahaDB store (identified by the kahaDB tag).
For more information, see:
http://activemq.apache.org/persistence.html
-->
<!--<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>-->
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#derby-ds"/>
</persistenceAdapter>
<!--
The systemUsage controls the maximum amount of space the broker will
use before disabling caching and/or slowing down producers. For more information, see:
http://activemq.apache.org/producer-flow-control.html
-->
<systemUsage>
<systemUsage>
<memoryUsage>
<memoryUsage percentOfJvmHeap="70" />
</memoryUsage>
<storeUsage>
<storeUsage limit="100 gb"/>
</storeUsage>
<tempUsage>
<tempUsage limit="50 gb"/>
</tempUsage>
</systemUsage>
</systemUsage>
<!--
The transport connectors expose ActiveMQ over a given protocol to
clients and other brokers. For more information, see:
http://activemq.apache.org/configuring-transports.html
-->
<transportConnectors>
<!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<!-- destroy the spring context on shutdown to stop jetty -->
<shutdownHooks>
<bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
</shutdownHooks>
</broker>
<bean id="derby-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
<!--
Enable web consoles, REST and Ajax APIs and demos
The web consoles requires by default login, you can disable this in the jetty.xml file
Take a look at ${ACTIVEMQ_HOME}/conf/jetty.xml for more details
-->
<import resource="jetty.xml"/>
</beans>
<!-- END SNIPPET: example -->
2.把mysql驱动jar包放到Activemq的lib文件夹下
3.手动在mysql数据库建一个名为activemq的数据库,并赋予建表的权限。
4.此时可以启动Activemq,并查看activemq数据库下新建了3个表:
注意,若在启动过程中出现如下错误:
重新启动就可以了。
5.运行发送者代码:
package com.satx.persistence;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
public class Sender {
private static final int SEND_NUMBER = 2;
public static void main(String[] args) {
// ConnectionFactory 接口(连接工厂) 用户用来创建到JMS提供者的连接的被管对象。
// JMS客户通过可移植的接口访问连接,这样当下层的实现改变时,代码不需要进行修改。
// 管理员在JNDI名字空间中配置连接工厂,这样,JMS客户才能够查找到它们。
// 根据消息类型的不同,用户将使用队列连接工厂,或者主题连接工厂。
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
// Connection 接口(连接) 连接代表了应用程序和消息服务器之间的通信链路。
// 在获得了连接工厂后,就可以创建一个与JMS提供者的连接。根据不同的连接类型,
// 连接允许用户创建会话,以发送和接收队列和主题到目标。
Connection connection = null;
// Session: 一个发送或接收消息的线程
// Session 接口(会话) 表示一个单线程的上下文,用于发送和接收消息。
// 由于会话是单线程的,所以消息是连续的,就是说消息是按照发送的顺序一个一个接收的。
// 会话的好处是它支持事务。如果用户选择了事务支持,会话上下文将保存一组消息,直到事务被提交才发送这些消息。
// 在提交事务之前,用户可以使用回滚操作取消这些消息。一个会话允许用户创建消息生产者来发送消息,创建消息消费者来接收消息。
Session session;
// Destination :消息的目的地;消息发送给谁.
// Destination 接口(目标) 目标是一个包装了消息目标标识符的被管对象,
// 消息目标是指消息发布和接收的地点,或者是队列,或者是主题。
// JMS管理员创建这些对象,然后用户通过JNDI发现它们。
// 和连接工厂一样,管理员可以创建两种类型的目标,点对点模型的队列,以及发布者/订阅者模型的主题。
Destination destination;
// MessageProducer:消息发送者
// MessageProducer 接口(消息生产者) 由会话创建的对象,用于发送消息到目标。
// 用户可以创建某个目标的发送者,也可以创建一个通用的发送者,在发送消息时指定目标。
MessageProducer producer;
// TextMessage message;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER, //null
ActiveMQConnection.DEFAULT_PASSWORD, //null
"tcp://localhost:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE); //1
destination = session.createQueue(RunServer.queueName);
// 得到消息生成者【发送者】
producer = session.createProducer(destination);
// 设置不持久化,可以更改
producer.setDeliveryMode(DeliveryMode.PERSISTENT); //2
// 构造消息
sendMessage(session, producer);
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
public static void sendMessage(Session session, MessageProducer producer)
throws Exception {
for (int i = 1; i <= SEND_NUMBER; i++) {
TextMessage message = session
.createTextMessage("ActiveMq 发送的消息" + i);
// 发送消息到目的地方
System.out.println("发送消息:" + i);
producer.send(message);
}
}
}
成功运行结果:
发送消息:1
发送消息:2
此时查看activemq数据库的activemq_msgs表,发现有两条数据:
package com.satx.persistence;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
public class Receiver {
public static void main(String[] args) {
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = null;
// Session: 一个发送或接收消息的线程
final Session session;
// Destination :消息的目的地;消息发送给谁.
Destination destination;
// 消费者,消息接收者
// MessageConsumer 接口(消息消费者) 由会话创建的对象,用于接收发送到目标的消息。
// 消费者可以同步地(阻塞模式),或异步(非阻塞)接收队列和主题类型的消息。
MessageConsumer consumer;
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
//queue_name跟sender的保持一致,一个创建一个来接收
destination = session.createQueue(RunServer.queueName);
consumer = session.createConsumer(destination);
// //第一种情况
// int i = 0;
// while (i < 3) {
// i++;
// TextMessage message = (TextMessage) consumer.receive();
// session.commit();
// // TODO something....
// System.out
// .println("收到消息:" +message.getText());
// }
// session.close();
// connection.close();
//----------------第一种情况结束----------------------
// 第二种方式
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message arg0) {
if(arg0 instanceof TextMessage){
try {
System.out.println("收到消息"+((TextMessage)arg0).getText());
session.commit();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
//第三种情况
// while (true) {
// Message msg = consumer.receive(1000);
// TextMessage message = (TextMessage) msg;
// if (null != message) {
// System.out.println("收到消息:" + message.getText());
// }
// }
} catch (Exception e) {
e.printStackTrace();
}
}
}
成功运行结果:
收到消息ActiveMq 发送的消息1
收到消息ActiveMq 发送的消息2
此时再查看表中的数据已经被消费了: