在我们生产过程中往往存在两个项目接口调用场景,但是这中场景下我们很难保证百分百的网络问题和服务问题,所在就会导致我们在调用接口的时候连接超时或者访问不到的情况发生,以致我们的数据丢失。
出现以上问题不用担心,本文就是重点介绍如何通过ActiveMQ的持久化操作解决请求丢失数据。
首先我们需要了解一下ActiveMQ的持久化方式,多的不说我们这里介绍两种持久化方式,一个是持久化到文件;一个是持久化到数据库,下面就逐一介绍:
1.持久化到文件
持久化到文件,默认保存方式为kahaDB。activemq.xml中持久化配置:
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
这是ActiveMQ的默认配置
假如设置发送消息时设置消息为持久化,这时候启动了broken服务器,消息发送者,但是消息接收者没有启动,那么持久化文件中会把消息保存到文件中;直到消息接受者接收消息之后会把消息记录删除。以下kahadb目录为保存的消息记录。
2.持久化到数据库中,如mysql和oracle;
首先需要下载数据库驱动包,这里使用的是mysql数据库,所以下载了mysql-connector-java-5.0.4-bin.jar,并把jar包放入到apache-activemq-5.8.0\lib目录下。
修改activemq.xml配置文件:
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#derby-ds"/>
</persistenceAdapter>
同时在activemq.xml文件的broken节点外面添加如下配置:
<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="root"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
在数据库中新建activemq数据库,这是启动activemq.bat后,会在数据库下新建三个表:
这时先启动消息发送者,会在activemq_msgs下看到多了一条记录。
再启动消息接受者,会看到表中记录已被删除。
active的配置方式已说完,现在来说一下怎么整合spring实现功能:
1.生产者的配置
web.xml加入我们activeMQ的配置文件
applicationContext-activeMQ.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:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd">
<!-- ActiveMQ 真正产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="activeMqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
<property name="userName" value="admin"></property>
<property name="password" value="admin"></property>
</bean>
<!-- 配置spring 管理 connectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="activeMqConnectionFactory" />
<property name="sessionCacheSize" value="100" />
</bean>
<!-- queue(队列模式),点对点 -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="pubSubDomain" value="false" />
<property name="explicitQosEnabled" value="true" /> <!-- deliveryMode, priority, timeToLive 的开关,要生效,必须配置为true,默认false-->
<property name="deliveryMode" value="2" /> <!-- 发送模式 DeliveryMode.NON_PERSISTENT=1:非持久 ; DeliveryMode.PERSISTENT=2:持久-->
</bean>
<!-- topic(主题,发布/订阅),一对多 -->
<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="pubSubDomain" value="true" />
<!-- 设置接收超时时间 60秒
<property name="receiveTimeout" value="60000"/>
-->
<!-- 消息不持久化 -->
<property name="explicitQosEnabled" value="false"></property>
</bean>
</beans>
生产者控制层(调用发送消息):
@Controller
@RequestMapping("test")
public class TestController {
@Autowired
TopicSender topicSender;
@RequestMapping("send")
@ResponseBody
public String sendMessage(){
System.out.println("开始发送消息");
topicSender.send("goodsAddTopic", "商品添加成功,开始更新商品索引库");
return "test success";
}
@RequestMapping("send2")
@ResponseBody
public String sendMessage2(){
System.out.println("开始发送消息-------------2");
topicSender.send("goods2AddTopic", "商品添加成功,开始更新商品索引库---------2");
return "test success";
}
}
TopicSender.java:
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
@Component
public class TopicSender {
@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsTemplate;
/**
* 发送一条消息到指定的队列(目标)
* @param queueName 队列名称
* @param message 消息内容
*/
public void send(String topicName,final String message){
jmsTemplate.send(topicName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(message);
}
});
}
}
注:TopicSender一定要被spring扫描不然会报空指针
2.消费者配置
web.xml与生产者一样
applicationContext-activeMQ.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:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd">
<!-- ActiveMQ 真正产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="activeMqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
<property name="userName" value="admin"></property>
<property name="password" value="admin"></property>
</bean>
<!-- 配置spring 管理 connectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="activeMqConnectionFactory" />
<property name="sessionCacheSize" value="100" />
</bean>
<!--这个是PTP目的地,一对多的 -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="goodsAddTopic,goods2AddTopic" />
</bean>
<!--这个是主题(topic)目的地,一对多的 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="goodsAddTopic,goods2AddTopic" />
</bean>
<!-- 消息监听类 -->
<bean id="goodsAddMessageListener" class="com.hoomsun.message.GoodsESMessageLister"/>
<!-- 消息监听器 -->
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"></property>
<property name="destination" ref="queueDestination"></property>
<property name="messageListener" ref="goodsAddMessageListener"></property>
</bean>
</beans>
GoodsESMessageLister.java
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
/**
* 消息监听器,消息的消费者
* @author back
*/
public class GoodsESMessageLister implements MessageListener{
@Override
public void onMessage(Message message) {
try {
Destination destination=message.getJMSDestination();
String topci=destination.toString();
System.out.println("topc---44444------"+topci);
TextMessage textMessage = (TextMessage) message;
System.out.println("=======商品添加成功,从消息队列中读取同步索引请求================"+textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
配置完成之后就可以测试,
①、先启动生产者;
②、访问生产者方法发送消息;
③、启动消费者,看消费者是否能接受到之前生产者发送的消息。
如果接收到证明配置成功。
最后贴上pom.xml中需用到的jar包
<!-- activemq -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.12.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
对你有帮助就记得关注一下,我会不定期的更新一些好的技术。