ActiveMQ 高级用法一、嵌入式MQ
在实际开发中,如果项目没能给太多资源,而现在业务中又需要用到MQ,可以考虑嵌入式MQ,嵌入式MQ不需要安装ActiveMQ,只需要导入相关依赖就可以
1、pom文件需导入依赖:(在前两篇关于MQ的依赖的基础上导入这个依赖)
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.14.5</version>
</dependency>
2、首先启动一个嵌入式MQ的服务,代码如下:
public class EmbedMQ {
public static void main(String[] args) throws Exception {
BrokerService brokerService = new BrokerService();
brokerService.setBrokerName("EmbedMQ");
brokerService.addConnector("tcp://localhost:62000");
brokerService.setManagementContext(new ManagementContext());
brokerService.start();
}
}
3、生产者端:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class EmbedJmsProducter {
//默认连接用户名
private static final String USERNAME= ActiveMQConnection.DEFAULT_USER;
//默认连接密码
private static final String PASSWORD= ActiveMQConnection.DEFAULT_PASSWORD;
//默认连接地址
private static final String BROKEURL= "tcp://localhost:62000";
//发送的消息数量
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();
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//destination = session.createQueue("HelloWAM");
destination = session.createTopic("EmbedMQ");
messageProducer = session.createProducer(destination);
for (int i = 0; i < SENDNUM; i++) {
String msg = "内置MQ" + i + " " + System.currentTimeMillis();
TextMessage message = session.createTextMessage(msg);
System.out.println("发送消息:" + msg);
messageProducer.send(message);
}
session.commit();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
}
消费者端:
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;
public class EmbedJmsConsumer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static final String BROKEURL = "tcp://localhost:62000";
public static void main(String[] args) {
ConnectionFactory connectionFactory;//连接工厂
Connection connection = null;//连接
Session session;//会话 接受或者发送消息的线程
Destination destination;//消息的目的地
MessageConsumer messageConsumer;//消息的消费者
//实例化连接工厂
connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD, BROKEURL);
try {
//通过连接工厂获取连接
connection = connectionFactory.createConnection();
//启动连接
connection.start();
//创建session
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建一个连接HelloWorld的消息队列
destination = session.createTopic("EmbedMQ");
//创建消息消费者
messageConsumer = session.createConsumer(destination);
messageConsumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
try {
System.out.println("Accept msg : "+ ((TextMessage) message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
} catch (JMSException e) {
e.printStackTrace();
}
}
}
4、测试
先启动服务,在启动消费者,最后启动生产者发送消息。
ActiveMQ高级用法二、消息持久化方案:
生产环境中,ActiveMQ可能挂掉,为了保证挂掉后消息不丢失,需要对消息进行持久化,ActiveMQ提供几种解决方案。
1、AMQ:基于文件存储,它具有写入速度快和容易恢复的特点。消息存储在一个个文件中,文件的默认大小为32M,如果一条消息的大小超过了32M,那么这个值必须设置大一点。当一个存储文件中的消息已经全部被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ适用于ActiveMQ5.3之前的版本。
2、KahaDB消息存储-提供了容量的提升和恢复能力,是现在的默认存储方式;KahaDB是基于文件的本地数据库储存形式,虽然没有AMQ的速度快,但是它具有强扩展性,恢复的时间比AMQ短,从5.4版本之后KahaDB做为默认的持久化方式。由于是默认的存储方案,即便不做任何配置,ActiveMQ启动时,也会启动KahaDB。这种情况文件所在位置是ActiveMQ安装路径下的/data/KahaDB子目录
3、JDBC消息存储-消息基于JDBC存储的,将数据存到数据库中;这种不是默认配置,如果想使用要做如下配置
修改配置文件 conf/ActiveMQ.xml
1.将:
<persistenceAdapter>
<kahaDB directory="${activemq.base}/data/kahadb"/>
</persistenceAdapter>
修改为:
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds "/>
</persistenceAdapter>
2.在</broker>标签后,增加数据源的配置:
<bean id="mysql-ds" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activemq?relaxAutoCommit=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC"/>
<property name="username" value="****"/>
<property name="password" value="****"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
其中数据库名activemq需要在mysql中提前创建好,relaxAutoCommit=true这个属性必须要有,其他属性根据自身数据库信息及业务配置
放入必须的jar包
将 mysql 的驱动包放到ActiveMQ/lib 包下,启动ActiveMQ,如果报错,查看data/activemq.log 文件,可能是缺少其他jar包,我启动时报错,根据启动日志显示缺少commons-dbcp2-2.5.0.jar和commons-pool2-2.5.0.jar这两个包,同样导入到ActiveMQ/lib目录下,再次启动,启动成功
查看数据库,发现多了三张表
activemq_acks:用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存,主要数据库字段如下: container:消息的destination sub_dest:如果是使用static集群,这个字段会有集群其他系统的信息 client_id:每个订阅者都必须有一个唯一的客户端id用以区分 sub_name:订阅者名称 selector:选择器,可以选择只消费满足条件的消息。条件可以用自定义属性实现,可支持多属性and和or操作 last_acked_id:记录消费过的消息的id
activemq_lock:在集群环境中才有用,只有一个Broker可以获得消息,称为Master Broker,其他的只能作为备份等待Master Broker不可用,才可能成为下一个Master Broker。这个表用于记录哪个Broker是当前的Master Broker。
activemq_msgs:用于存储消息,Queue和Topic都存储在这个表中。主要的数据库字段如下: id:自增的数据库主键 container:消息的destination msgid_prod:消息发送者客户端的主键 msg_seq:是发送消息的顺序,msgid_prod+msg_seq可以组成jms的messageid