一、activeMQ消息服务器的介绍及安装:https://blog.csdn.net/IT_CREATE/article/details/86656108
前言说明:发送方既可以是发送方也可以是接收方,只需要把发送方的配置和接收方的配置结合一下就可以了,但是尽量不要这么做。作为接收方,一个接收方也尽量只去监听一个目的地,多个目的地,用多个接收方分开去监听,一个接收方只去接收一个目的地的消息。职责要分离。
如何运用activeMQ?
一、消息发送方的编写
1、先创建一个maven项目,可以是web项目,也可以是普通java项目,我这里创建的是普通java项目,导入相关jar包
pom.xml文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ge</groupId>
<artifactId>activemqSend</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>activemqSend</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.14.RELEASE</spring.version>
</properties>
<dependencies>
<!-- 引入spring兼容activemq相关JAR包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- xbean 如<amq:connectionFactory /> -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.16</version>
</dependency>
<!-- 引入activemq核心包,以及连接池的相关JAR包 -->
<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>
<!-- 引入spring框架兼容junit单元测试框架的相关JAR包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<!-- maven-compiler-plugin 主要用于规范JDK编译的版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2、在src\main\resources文件夹下面编写你的配置文件,创建一个applicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:amq="http://activemq.apache.org/schema/core" 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-4.0.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd">
<!-- 开启spring容器的自动扫描功能 -->
<context:component-scan base-package="com.ge.as"></context:component-scan>
<!-- 配置如何去连接ActiveMQ,配置路径、用户名和密码 -->
<amq:connectionFactory id="amqConnectionFactory"
brokerURL="tcp://127.0.0.1:61616" userName="admin" password="admin" />
<!-- 大家可以认为:我们是在配连接池 -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
<property name="sessionCacheSize" value="100" />
</bean>
<!-- 定义spring针对消息服务器,封装的模板对象 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<!-- 定义默认使用的目的地,为队列默认目的地,名字取名为logs -->
<property name="defaultDestinationName" value="logs" />
</bean>
<!-- 配置特定目的地 -->
<!-- 定义消息队列(Queue) -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<!-- 设置消息队列的队列名字,名字取名为message -->
<constructor-arg>
<value>message</value>
</constructor-arg>
</bean>
<!-- 定义消息主题特定目的地(topic) -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<!-- 设置消息主题的主题名字,名字起名为message -->
<constructor-arg>
<value>message</value>
</constructor-arg>
</bean>
<!-- 定义更多的目的地……,但是需要修改ID -->
<!-- 假设该应用程序,就是一个发布者,不是任何消费者的话 ,配置已经结束 -->
</beans>
3、编写你要发布的东西,比如这里,我要发送一个对象到消息服务器,所以我要创建一个对象。
在这里要注意,接受端如果要接收到我的这个对象的话,包名要和服务器端的的包名一致,比如,服务器端要发布的对象的全路径是com.ge.as.bean.UserBean,那么接受端这个我们新建的类也得是com.ge.as.bean.UserBean,才能接收到这个对象,反序列化成功,因为对象反序列化的过程只要类的内部结构发生变化就会序列化失败。
com.ge.as.bean.UserBean代码:
//没贴get、set方法
public class UserBean implements Serializable {
private static final long serialVersionUID = -165462155168787109L;
private String userName;
private String pwd;
}
4、编写发布消息的方法类
package com.ge.as.send;
import java.io.Serializable;
import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
/**
* ActiveMQ支持的消息类型有:(其他类型的消息的编写和下面的一样,只是session中的创建消息的范式改变一下就可以)
*
* TextMessage ---- session.createTextMessage(msg); 传递的是:文本信息
*
* ObjectMessage ---- session.createObjectMessage(obj); 传递的是:对象信息
*
* MapMessage ---- 类推 传递的是:Map K-V信息
*
* BytesMessage 传递的是:byte数组信息
*
* StreamMessage 传递的是:流信息
*
*
* @author Administrator
*
*/
@Component
public class SendMessage {
@Resource
private JmsTemplate jmsTemplate;
/**
* 发送文本消息
* 针对默认目的地
* @param msg
*/
public void sendTextMessage(final String msg) {
jmsTemplate.send(new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// TODO Auto-generated method stub
return session.createTextMessage(msg);
}
});
}
/**
* 发送对象消息
* 针对默认目的地
* @param obj 序列化对象
*/
public void sendObjectMessage(final Serializable obj) {
jmsTemplate.send(new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// TODO Auto-generated method stub
return session.createObjectMessage(obj);
}
});
}
/**
* 向特定的目的地发送文本消息
* @param destination
* @param msg
*/
public void sendTextMessage(final Destination destination,final String msg) {
jmsTemplate.send(destination,new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// TODO Auto-generated method stub
return session.createTextMessage(msg);
}
});
}
/**
* 向特定的目的地发送对象消息
* @param destination
* @param msg
*/
public void sendObjectMessage(final Destination destination,final Serializable obj) {
jmsTemplate.send(destination,new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// TODO Auto-generated method stub
return session.createObjectMessage(obj);
}
});
}
}
5、编写测试类,测试上面发布消息的类的方法可用性(向activeMQ发布消息)
package com.ge.as.send;
import javax.annotation.Resource;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ge.as.bean.UserBean;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:applicationContext.xml"})
public class SendMessageTest {
//我们自己定义的发布消息的方法类
@Resource
private SendMessage sendMessage;
//特定的队列目的地用ActiveMQQueue类,具体指向哪个目的地,用配置文件中特定目的地的id名来指定
//特定的队列目的地,属性变量名为我们在applicationContext.xml中配置的特定队列目的地id名,和你配置中的特定目的地进行一个绑定,所以要一致
@Resource
private ActiveMQQueue queueDestination;
//特定的主题目的地用ActiveMQTopic类,具体指向哪个目的地,用配置文件中特定目的地的id名来指定
//特定的主题目的地,属性变量名为我们在applicationContext.xml中配置的特定主题目的地id名
@Resource
private ActiveMQTopic topicDestination;
//如果有多个特定目的地,那么在定义属性的时候就多定义几个属性,属性的名字要和你在
//applicationContext.xml中配置的特定目的地id名一致,就能代表那个具体的目的地了。
/**
* 定义消息的生产
*/
@Test
public void sendMsg() {
int i = 0;
while(true) {
//向默认的目的地发送消息
sendMessage.sendTextMessage("服务器向默认目的地发送的消息:" + i);
//向特定的队列目的地发送消息
sendMessage.sendTextMessage(queueDestination, "服务器发送的消息:" + i);
//向特定的主题目的地发送消息
UserBean user = new UserBean("张"+i+"麻子","123456");
sendMessage.sendObjectMessage(topicDestination, user);
i ++;
if(i == 20) {
break;
}
}
}
}
二、消息接收方的编写
1、先创建一个maven项目,可以是web项目,也可以是普通java项目,我这里创建的是普通java项目,导入相关jar包
pom.xml文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ge</groupId>
<artifactId>activemqReceive</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>activemqReceive</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.14.RELEASE</spring.version>
</properties>
<dependencies>
<!-- 引入spring兼容activemq相关JAR包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- xbean 如<amq:connectionFactory /> -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.16</version>
</dependency>
<!-- 引入activemq核心包,以及连接池的相关JAR包 -->
<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>
<!-- 引入spring框架兼容junit单元测试框架的相关JAR包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<!-- maven-compiler-plugin 主要用于规范JDK编译的版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2、定义接收数据的对象,因为上面发送消息端向主题中发布的是对象消息
对象的包名类名要和发送方发布的对象的包名类名一样,因为上面发送的对象是 com.ge.as.bean.UserBean。所以这里一样
com.ge.as.bean.UserBean代码:
//没贴get、set方法
public class UserBean implements Serializable {
private static final long serialVersionUID = -165462155168787109L;
private String userName;
private String pwd;
}
3、编写消息监听者(也称接受者),要实现MessageListener接口,实现onMessage方法(在配置中用到了这个监听程序)
package com.ge.ar.listener;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import org.springframework.stereotype.Component;
import com.ge.as.bean.UserBean;
/**
* 定义一个文本消息监听器
*
* @author Administrator
*
*/
@Component
public class ReceiveMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
try {
if (message instanceof TextMessage) {
TextMessage text = (TextMessage) message;
System.out.println("ReceiveMessageListener监听到了文本消息:" + text.getText());
} else if (message instanceof ObjectMessage) {
ObjectMessage obj = (ObjectMessage) message;
UserBean user = (UserBean) obj.getObject();
System.out.println(user);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
4、在src\main\resources文件夹下面编写你的配置文件,创建一个applicationContext.xml文件进行编写(我这里配置中只是去监听了主题中特定目的地message的消息)
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:amq="http://activemq.apache.org/schema/core" 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-4.0.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd">
<!-- 开启spring容器的自动扫描功能 -->
<context:component-scan base-package="com.ge.ar"></context:component-scan>
<!-- 配置如何去连接ActiveMQ,配置路径、用户名、密码 -->
<amq:connectionFactory id="amqConnectionFactory"
brokerURL="tcp://127.0.0.1:61616" userName="admin" password="admin" />
<!-- 大家可以认为:我们是在配连接池 -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
<property name="sessionCacheSize" value="100" />
</bean>
<!-- 配置目的地 -->
<!-- 定义消息队列特定目的地(Queue) 要和发送端一致,特别是队列名字,因为后面就要去监听这个目的地,发送端就是向这个目的地发送的消息-->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<!-- 设置消息队列的队列名字 -->
<constructor-arg>
<value>message</value>
</constructor-arg>
</bean>
<!-- 定义默认消息目的地(Queue)要和发送端一致,特别是队列名字,因为后面就要去监听这个目的地 发送端就是向这个目的地发送的消息-->
<bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue">
<!-- 设置消息队列的队列名字 -->
<constructor-arg>
<value>logs</value>
</constructor-arg>
</bean>
<!-- 定义特定消息主题目的地(topic),要和发送端一致,特别是主题名字,因为后面就要去监听这个目的地,发送端就是向这个目的地发送的消息 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<!-- 设置消息主题的主题名字 -->
<constructor-arg>
<value>message</value>
</constructor-arg>
</bean>
<!-- 显示注入消息监听容器(Queue),配置连接工厂,监听的目标是demoQueueDestination,监听器是上面定义的监听器 -->
<bean id="queueListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<!-- 定义监听的目的地,topicDestination是我们在上面代码中配置的 -->
<property name="destination" ref="topicDestination" />
<!-- 定义消息监听者,也可以称之为:接收者 ,receiveMessageListener是我们自己写的,就是上面那个监听器-->
<property name="messageListener" ref="receiveMessageListener" />
<!-- true是topic主题,false是queue 队列-->
<property name="pubSubDomain" value="true"></property>
<!-- 配置session的关闭原则,这里是客户端确认关闭-->
<property name="sessionAcknowledgeMode" value="2"></property>
</bean>
<!-- 如果想监听多个目的地,把上面这段监听代码复制一份,修改你监听的目的地,及接受者就可以了-->
<!-- 不过最好一个监听者一个程序,做到监听者分离-->
<!-- sessionAcknowledgeMode有四个值:
static final int AUTO_ACKNOWLEDGE = 1; 自动确认
static final int CLIENT_ACKNOWLEDGE = 2; 客户端手动确认
static final int DUPS_OK_ACKNOWLEDGE = 3; 自动批量确认
static final int SESSION_TRANSACTED = 0; 事务提交并确认-->
</beans>
5、编写测试类测试这个监听,看能拿到消息不
package com.ge.ar;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ReceiveMessageTest {
//开启程序加载文件
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
}
}