我们安装完ActiveMQ后就可以用程序运行一下了。
首先登陆http://localhost:8161/admin,账号密码默认为admin,创建一个队列:FirstQueue
接下来创建Java项目
引入Jar:activemq-all-5.9.0.jar
P2P模型
//P2P
session.createQueue("FirstQueue");
Sender
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("FirstQueue");
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage("test");
producer.send(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
Receiver
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
// 获取操作连接
//自动确认
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("FirstQueue");
MessageConsumer consumer = session.createConsumer(destination);
while (true) {
TextMessage message = (TextMessage)consumer.receive(100000);
if (null != message && message.getText().equals("test")) {
System.out.println("收到消息" + message.getText());
} else {
System.out.println("失败消息" + message.getText());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
思考:若消息在接收端处理失败怎么办?
//此时我们需要设置手动提交
Session session = connection.
createSession(false, Session.CLIENT_ACKNOWLEDGE);
//确认消息处理成功,消息处理成功时调用
message.acknowledge();
//消息重发,默认重发6次,消息异常时调用
//对CLIENT_ACKNOWLEDGE有效,对AUTO_ACKNOWLEDGE无效
session.recover();
Receiver 消息重发处理
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
// 获取操作连接
//自动确认
//session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//手动确认
Session session = connection.
createSession(false, Session.CLIENT_ACKNOWLEDGE);
Destination destination = session.createQueue("FirstQueue");
MessageConsumer consumer = session.createConsumer(destination);
while (true) {
TextMessage message = (TextMessage)consumer.receive(100000);
if (null != message && message.getText().equals("test")) {
System.out.println("收到消息" + message.getText());
//确认消息处理成功
message.acknowledge();
} else {
System.out.println("失败消息" + message.getText());
//消息重发,默认重发6次
//对CLIENT_ACKNOWLEDGE有效,对AUTO_ACKNOWLEDGE无效
session.recover();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
以上就是P2P模型的相关使用介绍
订阅模型
//订阅
session.createTopic("FirstTopic");
Sender
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic createTopic = session.createTopic("FirstTopic");
MessageProducer producer = session.createProducer(createTopic);
TextMessage message = session.createTextMessage("test");
producer.send(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
Receiver
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
//自动确认
//session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//手动确认
Session session = connection.
createSession(false, Session.CLIENT_ACKNOWLEDGE);
Topic createTopic = session.createTopic("FirstTopic");
MessageConsumer consumer = null;
//非持久化方式
consumer = session.createConsumer(createTopic);
while (true) {
TextMessage message = (TextMessage)consumer.receive(100000);
if (null != message && message.getText().equals("test")) {
System.out.println("收到消息" + message.getText());
//确认消息处理成功
message.acknowledge();
} else {
System.out.println("失败消息" + message.getText());
//消息重发,默认重发6次
//对CLIENT_ACKNOWLEDGE有效,对AUTO_ACKNOWLEDGE无效
session.recover();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
思考:订阅模型中,接收端必须先启动,并且一直保持启动状态才能接收,如何改善,请继续往下看
订阅模型持久化
Mq持久化默认配置是在mq/conf/activemq.xml中
<!-- mq持久化产生文件的默认地址 -->
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
Sender修改send方式
/**
* 持久化
* DeliveryMode.PERSISTENT 持久化
* 1 : 优先级
* 1000*60*60*24 : 持久化的时间 毫秒
*/
producer.send(message, DeliveryMode.PERSISTENT, 1, 1000*60*60*24);
Receiver修改
//1、设置客户端ID, 可以任意写 (注:ID不能重复,多个客户端多个独立ID)
connection.setClientID("receiver-1");
//2、使用持久化方式
//consumer = session. createDurableSubscriber(createTopic, "receiver-1");
订阅模型持久化
Sender
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic createTopic = session.createTopic("FirstTopic");
MessageProducer producer = session.createProducer(createTopic);
TextMessage message = session.createTextMessage("test");
//producer.send(message);
/**
* 持久化
* DeliveryMode.PERSISTENT 持久化
* 1 : 优先级
* 1000*60*60*24 : 持久化的时间 毫秒
*/
producer.send(message, DeliveryMode.PERSISTENT, 1, 1000*60*60*24);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
Receiver
Connection connection = null;
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616");
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
//设置客户端ID, 可以任意写 (注:ID不能重复,多个客户端多个独立ID)
connection.setClientID("receiver-1");
// 启动
connection.start();
//自动确认
//session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//手动确认
Session session = connection.
createSession(false, Session.CLIENT_ACKNOWLEDGE);
Topic createTopic = session.createTopic("FirstTopic");
MessageConsumer consumer = null;
//非持久化方式
//consumer = session.createConsumer(createTopic);
//使用持久化方式
consumer = session. createDurableSubscriber(createTopic, "receiver-1");
while (true) {
TextMessage message = (TextMessage)consumer.receive(100000);
if (null != message && message.getText().equals("test")) {
System.out.println("收到消息" + message.getText());
//确认消息处理成功
message.acknowledge();
} else {
System.out.println("失败消息" + message.getText());
//消息重发,默认重发6次
//对CLIENT_ACKNOWLEDGE有效,对AUTO_ACKNOWLEDGE无效
session.recover();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
订阅模型持久化到MySQL数据库
1> 在mq/lib包下放入MySQL驱动 mysql-connector-java-5.1.16-bin.jar
2> 修改mq/conf/activemq.xml
<!-- 注释掉默认持久化方式 -->
<!--
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
-->
<!-- 使用JDBC方式持久化 -->
<persistenceAdapter>
<jdbcPersistenceAdapter directory="${activemq.data}/data" dataSource="#MySQL-DS"/>
</persistenceAdapter>
<!-- 添加数据源 -->
<!-- MySQL DataSource -->
<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/testmq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
重启mq,即可实现持久化到数据库中
Spring整合ActiveMQ
引入pom文件
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
MQ生产者
spring-queue.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--监听MQ状态-->
<bean id="activeMQTransportListener"
class="com.sino.jms.ActiveMQTransportListener"/>
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
<bean id="targetConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<!--非集群方式连接-->
<!--<property name="brokerURL" value="tcp://127.0.0.1:61616"/>-->
<!--以集群方式连接-->
<property name="brokerURL" value="failover:(tcp://127.0.0.1:61616)"/>
<!--
<property name="brokerURL"
value="failover:(tcp://localhost:61616,tcp://localhost:61617)"/>
-->
<!--监听mq状态-->
<property name="transportListener" ref="activeMQTransportListener"/>
<!--
从ActiveMQ5.12.2 开始,为了增强这个框架的安全性,
ActiveMQ将强制用户配置可序列化的包名,
trustAllPackages=true是将所有包都添加为可信任
-->
<property name="trustAllPackages" value="true"/>
<!--配置消息重发策略-->
<property name="redeliveryPolicy">
<bean class="org.apache.activemq.RedeliveryPolicy">
<!--启用指数倍数递增的方式增加延迟时间,默认为false-->
<property name="useExponentialBackOff" value="true"/>
<!--
消息处理异常后重新处理次数,-1:无限次,0:不处理,默认为6
useExponentialBackOff = true 时有效
-->
<property name="maximumRedeliveries" value="3"/>
<!--初始重发延迟时间(毫秒)-->
<property name="initialRedeliveryDelay" value="100"/>
<!--
启用防止冲突功能,因为消息接收时是可以使用多线程并发处理的,
应该是为了重发的安全性,避开所有并发线程都在同一个时间点
进行消息接收处理,默认为false
-->
<property name="useCollisionAvoidance" value="true"/>
<!--拖延时间倍数,必须要大于1.0-->
<property name="backOffMultiplier" value="1.5"/>
<!--指定死信队列,需要MQ开启死信队列-->
<!--<property name="destination" ref="queueTextDestination"/>-->
</bean>
</property>
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<!--
目标ConnectionFactory对应真实的
可以产生JMS Connection的ConnectionFactory
-->
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!--
这个connectionFactory对应的是我们定义的
Spring提供的那个ConnectionFactory对象
-->
<property name="connectionFactory" ref="connectionFactory"/>
<!--内部的consumer在receive方法中阻塞的时间,默认是1秒-->
<property name="receiveTimeout" value="3000" />
<!-- NON_PERSISTENT非持久化 1 ,PERSISTENT持久化 2 -->
<!--死信队列 : 缺省持久消息过期,会被送到DLQ,非持久消息不会送到DLQ-->
<property name="deliveryMode" value="2"/>
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<!--
这个connectionFactory对应的是我们定义的
Spring提供的那个ConnectionFactory对象
-->
<property name="connectionFactory" ref="connectionFactory"/>
<!--Queue队列-->
<property name="pubSubDomain" value="false"/>
<!--内部的consumer在receive方法中阻塞的时间,默认是1秒-->
<property name="receiveTimeout" value="3000" />
<!-- NON_PERSISTENT非持久化 1 ,PERSISTENT持久化 2 -->
<!--死信队列 : 缺省持久消息过期,会被送到DLQ,非持久消息不会送到DLQ-->
<property name="deliveryMode" value="2"/>
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
<!--
这个connectionFactory对应的是我们定义的
Spring提供的那个ConnectionFactory对象
-->
<property name="connectionFactory" ref="connectionFactory"/>
<!--Topic队列-->
<property name="pubSubDomain" value="false"/>
<!--内部的consumer在receive方法中阻塞的时间,默认是1秒-->
<property name="receiveTimeout" value="3000" />
<!-- NON_PERSISTENT非持久化 1 ,PERSISTENT持久化 2 -->
<!--死信队列 : 缺省持久消息过期,会被送到DLQ,非持久消息不会送到DLQ-->
<property name="deliveryMode" value="2"/>
</bean>
<!--引入工具类,封装JMS常用方法-->
<bean id="queueSender" class="com.sino.jms.QueueSender">
<property name="jmsTemplate" ref="jmsQueueTemplate"/>
</bean>
<bean id="topicSender" class="com.sino.jms.TopicSender">
<property name="jmsTemplate" ref="jmsTopicTemplate"/>
</bean>
</beans>
ActiveMQTransportListener (MQ状态监听)
package com.sino.jms;
import org.apache.activemq.transport.TransportListener;
import java.io.IOException;
public class ActiveMQTransportListener implements TransportListener {
/**
* 对消息传输命令进行监控
* @param command
*/
@Override
public void onCommand(Object command) {
System.out.println("ActiveMQ Execute Cmd");
}
/**
* 对监控到的异常进行触发
* @param e
*/
@Override
public void onException(IOException e) {
System.out.println("****************↓↓↓异常↓↓↓*****************");
e.printStackTrace();
System.out.println("ActiveMQ Exception Occurred");
}
/**
* 当failover时触发
*/
@Override
public void transportInterupted() {
System.out.println("ActiveMQ Server Connection Is Broken...");
System.out.println("transportInterupted -> 消息服务器连接发生中断...");
}
/**
* 监控到failover恢复后进行触发
*/
@Override
public void transportResumed() {
System.out.println("ActiveMQ Server Reconnected ...");
System.out.println("transportResumed -> 消息服务器连接已恢复...");
}
}
MQ工具类
Sender.java
package com.sino.jms;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Session;
import java.io.Serializable;
import java.util.Map;
/**
* 队列消息发送类
*/
public class Sender {
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
/**
* 发送一条消息到指定的队列(目标)
* @param queueName 队列名称
* @param message 消息内容
*/
public void send(String queueName,
final Serializable message) {
jmsTemplate.send(queueName, new MessageCreator() {
public Message createMessage(Session session)
throws JMSException {
return session.createObjectMessage(message);
}
});
}
public void sendString(String queueName,
final String message) {
jmsTemplate.send(queueName, new MessageCreator() {
public Message createMessage(Session session)
throws JMSException {
return session.createTextMessage(message);
}
});
}
}
QueueSender.java
package com.sino.jms;
import org.springframework.jms.core.JmsTemplate;
/**
* 队列消息发送类
*/
public class QueueSender extends Sender {
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
super.setJmsTemplate(jmsTemplate);
}
}
TopicSender.java
package com.sino.jms;
import org.springframework.jms.core.JmsTemplate;
/**
* 订阅消息发送
*/
public class TopicSender extends Sender {
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
super.setJmsTemplate(jmsTemplate);
}
}
MQ生产消息Demo
@Autowired
private QueueSender queueSender;
@Autowired
private TopicSender topicSender;
@RequestMapping("/delByIds")
public Result delByIds (Long[] ids){
queueSender.send("Sino.Queue.Solr.Delete",ids);
topicSender.send("Sino.Topic.Page.Delete",ids);
}
MQ消费者(注解版)
在以上生产者的基础上,继续配置消费者
spring-mq-consume-annotation.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<import resource="spring-mq.xml"/>
<bean id="jmsListenerContainerFactory"
class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="connectionFactory"/>
<!--开启事务-->
<property name="sessionTransacted" value="true"/>
<!--设置手动确认提交-->
<property name="sessionAcknowledgeMode" value="2"/>
</bean>
<!--开启注解-->
<jms:annotation-driven container-factory="jmsListenerContainerFactory"/>
</beans>
消费者
@Component
public class ListenerAnnotationDemo extends MessageListenerAdapter {
//concurrency="5-10" 允许的并发数
//@JmsListener(destination="queue_text1",concurrency="5-10")
@JmsListener(destination="queue_text")
public void onMessagehehe(Message message, Session session)
throws JMSException {
try {
TextMessage textMessage = (TextMessage) message;
System.out.println("接收到消息: " + textMessage.getText());
} catch (Exception e) {
e.printStackTrace();
}
}
}
MQ消费者(XML版1.0)
spring-queue-consume.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<import resource="spring-mq.xml"/>
<!--这个是队列目的地,点对点的 文本信息-->
<bean id="queueTextDestination"
class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue_text"/>
</bean>
<bean id="myMessageListener" class="com.sino.jms.queue.QueueListener"></bean>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueTextDestination" />
<property name="messageListener" ref="myMessageListener" />
<!--开启事务-->
<property name="sessionTransacted" value="true"/>
<!--设置手动确认提交-->
<property name="sessionAcknowledgeMode" value="2"/>
</bean>
<!--如果配置多个队列或订阅,将上面的三个Bean重新配置一遍即可-->
</beans>
QueueListener.java (消费者)
public class QueueListener implements MessageListener {
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
System.out.println("接收到消息: " + textMessage.getText());
} catch (Exception e) {
e.printStackTrace();
}
}
}
MQ消费者(XML版2.0)
spring-queue-consume.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<import resource="spring-mq.xml"/>
<bean id="myMessageListener" class="com.sino.jms.queue.QueueListener"/>
<jms:listener-container
destination-type="queue" container-type="default"
connection-factory="connectionFactory" acknowledge="client" >
<!-- 可写多个监听器 -->
<jms:listener destination="queue_text" ref="myMessageListener"/>
</jms:listener-container>
</beans>
开启MQ死信队列
修改mq的配置文件(conf/activemq.xml) , 打开如下地方的注释即可
<policyEntry topic=">" >
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix= "DLQ."
useQueueForQueueMessages= "true" />
</deadLetterStrategy>
<pendingMessageLimitStrategy>
<constantPendingMessageLimitStrategy limit="1000"/>
</pendingMessageLimitStrategy>
</policyEntry>
至此,Mq在Java中的应用就介绍完了