工程及实验报告书下载
页面底部为实习指导书
①运行消息服务器ActiveMQ:下载apache-activemq-5.4.3后随意解压并运行bin目录下的activemq.bat(若闪退则运行\bin\win32下的activemq.bat)
②cmd输入netstat -an|find “61616”,显示如图则成功
netstat -an|find “61616”
③登录管理界面
浏览器中输入:http://localhost:8161/admin/
在此处点击Queues可以查看消息队列的情况
以下为源码或直接工程下载
首先往Java工程内导入Jar包:activemq-all-5.4.3.jar,该文件在apache-activemq-5.4.3\lib中可找到
接收端
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Receiver {
public static void main(String[] args) {
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = null;
// Session: 一个发送或接收消息的线程
Session session;
// Destination :消息的目的地;消息发送给谁.
Destination destination;
// 消费者,消息接收者
MessageConsumer consumer;
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
// 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
destination = session.createQueue("FirstQueue");
consumer = session.createConsumer(destination);
while (true) {
//设置接收者接收消息的时间,为了便于测试,这里设定为100s
TextMessage message = (TextMessage) consumer.receive(100000);
if (null != message) {
System.out.println("收到消息" + message.getText());
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
}
发送端
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Sender {
private static final int SEND_NUMBER = 5;
public static void main(String[] args) {
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = null;
// Session: 一个发送或接收消息的线程
Session session;
// Destination :消息的目的地;消息发送给谁.
Destination destination;
// MessageProducer:消息发送者
MessageProducer producer;
// TextMessage message;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
// 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
destination = session.createQueue("FirstQueue");
// 得到消息生成者【发送者】
producer = session.createProducer(destination);
// 设置不持久化,此处学习,实际根据项目决定
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 构造消息,此处写死,项目就是参数,或者方法获取
sendMessage(session, producer);
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
public static void sendMessage(Session session, MessageProducer producer)
throws Exception {
for (int i = 1; i <= SEND_NUMBER; i++) {
TextMessage message = session
.createTextMessage("ActiveMq 发送的消息" + i);
// 发送消息到目的地方
System.out.println("发送消息:" + "ActiveMq 发送的消息" + i);
producer.send(message);
}
}
}
启动ActiveMQ服务器后,运行Receiver后登录http://localhost:8161/admin/可以发现Queue已经新建了一个队列
接下来运行Sender类会呈现5条输出,实际上是向ActiveMQ服务器中的“FirstQueue”队列中发送了5条消息,并消费了。
本实验要求使用:
①接收类必须实现为一个单独的线程
②至少使用2个以上的队列
即:
ActiveMQ实现单线程多队列
发送端1
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Sender {
private static final int SEND_NUMBER = 5;
ConnectionFactory connectionFactory;//连接工厂,JMS 用它创建连接
Connection connection = null;//JMS 客户端到JMS Provider 的连接
Session session;//一个发送或接收消息的线程
Destination destination;//消息的目的地
MessageProducer producer;//生产者,消息发送者
Sender() {
// TextMessage message;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
connection = connectionFactory.createConnection();//构造从工厂得到连接对象
connection.start();//启动
session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);//获取操作连接,此处是Boolean.TRUE,是否支持事务,如果为true,则会忽略第二个参数
destination = session.createQueue("AQueue");//获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
producer = session.createProducer(destination);// 得到消息生成者【发送者】
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);// 设置不持久化,此处学习,实际根据项目决定
sendMessage(session, producer);// 构造消息,此处写死,项目就是参数,或者方法获取
session.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
public void sendMessage(Session session, MessageProducer producer) throws Exception {
for (int i = 1; i <= SEND_NUMBER; i++) {
TextMessage message = session.createTextMessage(this.getClass().getName()+" 发送的消息" + i);
System.out.println(this.getClass().getName()+" 发送的消息" + i);// 发送消息到目的地方
producer.send(message);
}
}
public static void main(String[] args) {
new Sender();
}
}
发送端2,直接将以上发送端Copy一份,并把队列改成“BQueue”即可
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Sender2 {
private static final int SEND_NUMBER = 5;
ConnectionFactory connectionFactory;//连接工厂,JMS 用它创建连接
Connection connection = null;//JMS 客户端到JMS Provider 的连接
Session session;//一个发送或接收消息的线程
Destination destination;//消息的目的地
MessageProducer producer;//生产者,消息发送者
Sender2() {
// TextMessage message;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
connection = connectionFactory.createConnection();//构造从工厂得到连接对象
connection.start();//启动
session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);//获取操作连接,此处是Boolean.TRUE,是否支持事务,如果为true,则会忽略第二个参数
destination = session.createQueue("BQueue");//获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
producer = session.createProducer(destination);// 得到消息生成者【发送者】
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);// 设置不持久化,此处学习,实际根据项目决定
sendMessage(session, producer);// 构造消息,此处写死,项目就是参数,或者方法获取
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
public void sendMessage(Session session, MessageProducer producer) throws Exception {
for (int i = 1; i <= SEND_NUMBER; i++) {
TextMessage message = session.createTextMessage(this.getClass().getName()+" 发送的消息" + i);
System.out.println(this.getClass().getName()+" 发送的消息" + i);// 发送消息到目的地方
producer.send(message);
}
}
public static void main(String[] args) {
new Sender2();
}
}
错误的接收端
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class WrongReceiver{
ConnectionFactory connectionFactory;//连接工厂,JMS 用它创建连接
Connection connection = null;//JMS 客户端到JMS Provider 的连接
Session session;//一个发送或接收消息的线程
Destination destination;//A消息的目的地
MessageConsumer consumer;//A消费者,消息接收者
Destination destination2;//B消息的目的地
MessageConsumer consumer2;//B消费者,消息接收者
WrongReceiver() {
try {
System.out.println("ActiveMQ 服务器正在接收信息");
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
connection = connectionFactory.createConnection();//构造从工厂得到连接对象
connection.start();//启动
session = connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);//获取操作连接,此处是Boolean.FALSE,第二个参数为false时,paramB的值可为Session.AUTO_ACKNOWLEDGE,Session.CLIENT_ACKNOWLEDGE,DUPS_OK_ACKNOWLEDGE其中一个,此处为自动确认,客户端发送和接收消息不需要做额外的工作。哪怕是接收端发生异常,也会被当作正常发送成功。
destination = session.createQueue("AQueue");
consumer = session.createConsumer(destination);
destination2 = session.createQueue("BQueue");
consumer2 = session.createConsumer(destination2);
while (true) {
TextMessage message = (TextMessage) consumer.receive(100000);//设置接收者接收消息的时间,为了便于测试,这里设定为100s
TextMessage message2 = (TextMessage) consumer2.receive(100000);
if (null != message) {
System.out.println("收到A消息" + message.getText());
}
else if (null != message2) {
System.out.println("收到B消息" + message2.getText());
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
public static void main(String[] args) {
new WrongReceiver();
}
}
为了实现两个队列,这里直接粗暴地将上面的Demo里的Queue改成了两个,并且直接接收信息。
①运行后WrongReceiver类
②运行Sender类
③运行Sender2类
此时会发现ActiveMQ服务器只会接收到Sender发出的A队列内的信息
直接观察,运行接收端后再运行Sender类发现此时Sender类已阻塞了
经过分析,接收端的while循环接收两队列信息阻塞了
解决方案
第一个是直接new run一个Thread后接收不同队列即可
第二个是让接收不阻塞
发现原来是接收端的receive(100000)这个方法互相阻碍了,于是将receive(100000)改成receiveNoWait()
直接运行发现只能接收一次信息接收端就关闭了,原来是else { break; }直接跳出循环了,将这句删掉即可。
以下给出正确的接收端
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Receiver{
ConnectionFactory connectionFactory;//连接工厂,JMS 用它创建连接
Connection connection = null;//JMS 客户端到JMS Provider 的连接
Session session;//一个发送或接收消息的线程
Destination destination;//A消息的目的地
MessageConsumer consumer;//A消费者,消息接收者
Destination destination2;//B消息的目的地
MessageConsumer consumer2;//B消费者,消息接收者
Receiver() {
try {
System.out.println("ActiveMQ 服务器正在接收信息");
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
connection = connectionFactory.createConnection();//构造从工厂得到连接对象
connection.start();//启动
session = connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);//获取操作连接,此处是Boolean.FALSE,第二个参数为false时,paramB的值可为Session.AUTO_ACKNOWLEDGE,Session.CLIENT_ACKNOWLEDGE,DUPS_OK_ACKNOWLEDGE其中一个,此处为自动确认,客户端发送和接收消息不需要做额外的工作。哪怕是接收端发生异常,也会被当作正常发送成功。
destination = session.createQueue("AQueue");
consumer = session.createConsumer(destination);
destination2 = session.createQueue("BQueue");
consumer2 = session.createConsumer(destination2);
while (true) {
TextMessage message = (TextMessage) consumer.receiveNoWait();//设置接收者接收消息的时间,为了便于测试,这里设定为100s
TextMessage message2 = (TextMessage) consumer2.receiveNoWait();
if (null != message) {
System.out.println("收到A消息" + message.getText());
}
else if (null != message2) {
System.out.println("收到B消息" + message2.getText());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
public static void main(String[] args) {
new Receiver();
}
}
①运行Receiver类
②运行Sender类
③运行Sender2类
Console中观察到:
实习指导书:
实习三 消息中间件应用开发
一 实习目的
利用消息中间件接口JMS、消息服务器ActiveMQ 和Java Swing实现一个简单的聊天工具,掌握消息中间件的应用。
二 实习要求
1、开发环境
Windows 7/XP,Eclipse, JDK1.6, apache-activemq-5.4.3, Java Swing
2、功能要求
(1)实现界面化的聊天工具,支持二人之间互发消息。
(2)界面上必须标注软件版权信息,包括姓名、学号等个性化信息。
(3)发送消息过程中,发送这首先把消息发送到消息服务器ActiveMQ,接收者从消息服务器上取消息;消息发送者和接收者不需要同时运行(在线),实现即使对方处在离线状态下也可以进行消息的发送和接收。
三 实习过程
1、ActiveMQ 安装和配置
(1)解压缩到apache-activemq-5.4.3-bin.zip到一个目录,例如C:\ apache-activemq-5.4.3
(2)配置文件在C:\apache-activemq-5.4.3\conf目录中:activemq.xml、credentials.properties、log4j.properties(本次实习不需要配置)。
(3)启动ActiveMQ:运行C:\ apache-activemq-5.4.3\bin\activemq.bat
(4)测试
ActiveMQ默认使用的TCP连接端口是61616, 通过查看该端口的信息可以测试ActiveMQ是否成功启动 netstat -an|find “61616”
在CMD下输入:netstat -an|find “61616” 显示下列信息表示成功。
TCP 0.0.0.0:61616 0.0.0.0:0 LISTENING
(5)登陆管理界面(本次实习不需要进入管理界面)
浏览器中输入:http://localhost:8161/admin/,用户名密码:admin,admin
2、开发
(1)在eclipse中导入并运行MessageMiddleWare中的三个例子,了解消息发送者、接收者编程。
(2)在建立一个工程,导入库文件activemq-all-5.4.3.jar(在apache-activemq-5.4.3\lib可找到该文件);也可直接在MessageMiddleWare工程中开发。
(3)使用Java Swing开发界面,界面上包括消息发送窗口、接收窗口(或二者在同一个窗口)、发送按钮等,界面下方需显示个性化的版权信息。
(4)参考MessageMiddleWare中的例子,编写消息发送类和接收类。发送类中需要连接ActiveMQ 服务器,创建队列,发送消息;接收类中需要ActiveMQ 服务器,读取发送者发送消息所用的队列。接收类必须实现为一个单独的线程,时刻侦听是否有消息到来。
(5)至少使用2个以上的队列,A给B发送消息时使用一个队列,B给A发送时使用另一个队列(若使用同一个队列,可能导致消息混乱)。
(6)开发完毕,打包为可运行包(不要把MessageMiddleWare放进去),双击可以直接运行。
3、相关软件见附件