消息队列 activeMQ+spring(测试dome)
使用maven创建项目
mvn archetype:generate
背景
base-db--->kettle--->warehouse-db(X),warehouse-db<--(mq)<--server-->base-db;
方案
使用消息队列技术将数据同步到仓库中,并在指定时间进行数据修复,达到数据的实时查询.技术难点是消息队列的实现.
实现
环境
jdk1.8+activemq(docker)+spring+maven
环境搭建
idea(社区版)搭建spring+maven环境
pom.xml(非完整)
<properties>
<sb.version>5.1.5.RELEASE</sb.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13-beta-3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${sb.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${sb.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${sb.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${sb.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${sb.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.5.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xbean/xbean-spring -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>4.14</version>
</dependency>
</dependencies>
创建一个消息实体类
消息需要进行序列化操作
package com.mq.core.now;
import java.io.Serializable;
public class Spittle implements Serializable{
private String name;
private String age;
public Spittle(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "name:"+name+",age:"+age;
}
}
创建接口
只提供简单的发送消息以及接收消息,本文实现的是点对点消息队列操作,对于主题订阅广播读者自行尝试
package com.mq.core.now;
public interface AlertService {
/**
*
* @param spittle
*/
void sendSpittleAlert(Spittle spittle,String spittleName);
void sendSpittleAlert(Spittle spittle);
public Spittle receiveSpittleAlert();
public Spittle receiveSpittleAlert(String spittleName);
}
接口实现类
package com.mq.core.now;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.support.JmsUtils;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Session;
public class AlertServiceImpl implements AlertService {
/**
* 注入jms模板
* @param jmsOperations
*/
@Autowired
private JmsOperations jmsOperations;
/**
* 发送消息
* @param spittle
*/
@Override
public void sendSpittleAlert(final Spittle spittle) {
/**
* 地址,创建消息
*/
jmsOperations.send((Session session) -> {
return session.createObjectMessage(spittle);
});
}
/**
* 发送消息(以指定的消息名称)
* @param spittle
*/
@Override
public void sendSpittleAlert(final Spittle spittle,String spittleName) {
/**
* 地址,创建消息
*/
jmsOperations.send(spittleName,(Session session) -> session.createObjectMessage(spittle));
}
/**
* 接收消息(同步的,需要等待消息的到来)
* @return
*/
@Override
public Spittle receiveSpittleAlert() {
try {
ObjectMessage receiveMessage = (ObjectMessage) jmsOperations.receive();
return (Spittle) receiveMessage.getObject();
} catch (JMSException e) {
//抛出异常
throw JmsUtils.convertJmsAccessException(e);
}
}
/**
* 获取指定队列名称的消息
*/
@Override
public Spittle receiveSpittleAlert(String spittleName) {
try {
ObjectMessage receiveMessage = (ObjectMessage) jmsOperations.receive(spittleName);
return (Spittle) receiveMessage.getObject();
} catch (JMSException e) {
//抛出异常
throw JmsUtils.convertJmsAccessException(e);
}
}
}
spring-config.xml
<?xml version="1.0" encoding="utf-8" ?>
<!-- xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"-->
<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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:amq="http://activemq.apache.org/schema/core"
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
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<!-- <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"-->
<!-- p:brokerURL="tcp://localhost:61616"/>-->
<amq:connectionFactory id="connectionFactory" brokerURL="tcp://localhost:61626"/>
<bean id="alterService" class="com.mq.core.now.AlertServiceImpl"/>
<bean id="spittleHandler" class="com.mq.core.now.SpittleAlertHandler"/>
<!-- 消息监听器 -->
<jms:listener-container connection-factory="connectionFactory" >
<jms:listener destination="spittle.alter.queue" ref="spittleHandler" method="handlerSpittleAlter"/>
</jms:listener-container>
<bean id="messageConverter" class="org.springframework.jms.support.converter.MappingJackson2MessageConverter"/>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"
c:_-ref="connectionFactory"
p:defaultDestinationName="spittle.alter.queue"
p:messageConverter-ref="messageConverter"/>
</beans>
测试
package com.mq;
import com.mq.core.now.AlertService;
import com.mq.core.now.Spittle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-config.xml"})
public class TestActiveMQ {
@Autowired
private AlertService alertService;
@Test
public void test01(){
for (int i = 0; i < 3 ; i++) {
System.out.printf("----发送消息----");
Spittle xuzz = new Spittle("xuzz", "23"+i);
alertService.sendSpittleAlert(xuzz);
System.out.println("消息发送结束");
}
}
@Test
public void testPOP(){
System.out.printf("----接收消息消息----");
Spittle spittle = alertService.receiveSpittleAlert();
System.err.println(spittle.toString());
}
@Test
public void testPOP1(){
while(true){
System.err.println(alertService.receiveSpittleAlert("yb-push").toString());
new Thread(()-> {
try {
Thread.sleep(1000L);
System.out.println("------------"+Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
@Test
public void testPOP2(){
while(true){
System.err.println(alertService.receiveSpittleAlert("yb-push").toString());
new Thread(()-> {
try {
Thread.sleep(1000L);
System.out.println("------------"+Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
在接收信息时候,消费者可能需要等到消息到来之后才能完成动作,否则需要一直等待消息的到来.一直占用资源,此时可以使用消息监听器来实现消息的异步接收.
package com.mq.core.now;
import org.springframework.beans.factory.annotation.Autowired;
/**
* spring MDP 异步接收消息和处理消息
*/
public class SpittleAlertHandler {
@Autowired
private AlertService alertService;
/**
* 异步处理数据处理消息
* @param spittle
*/
public void handlerSpittleAlter(Spittle spittle){
//...这里可以编写自定义的代码
//重新发送给我们想要的消费者,
alertService.sendSpittleAlert(spittle,"yb-push");
}
}
文章写的比较简单,很多地方没有讲到.后续的文章或者本文章会继续完善