ActiveMQ版本:5.9.1
JDK版本:1.6_45
一,解压安装包,并赋权限
[hadoop@fedora1 ~]$ tar -xzf apache-activemq-5.9.1-bin.tar.gz
[hadoop@fedora1 ~]$ chmod -R 775 apache-activemq-5.9.1
二,修改ActiveMQ启动文件
[hadoop@fedora1 ~]$ cd apache-activemq-5.9.1/bin
[hadoop@fedora1 bin]$ vi activemq
搜索JAVA,添加JAVA_HOME变量(如果设置了JAVA_HOME环境变量,则不需该步)
# Location of the java installation
# Specify the location of your java installation using JAVA_HOME, or specify the
# path to the "java" binary using JAVACMD
# (set JAVACMD to "auto" for automatic detection)
JAVA_HOME="/home/hadoop/jdk1.6.0_45"
JAVACMD="auto"
也可以修改内存参数:
# Set jvm memory configuration
if [ -z "$ACTIVEMQ_OPTS_MEMORY" ] ; then
ACTIVEMQ_OPTS_MEMORY="-Xms1G -Xmx1G"
fi
三,修改ActiveMQ的配置
1,broker配置:
[hadoop@fedora1 bin]$ vi ../conf/activemq.xml
broker策略配置:
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" producerFlowControl="true">
<!-- 如果一个消费者消费消息的速度比较慢,这会对非持久化主题产生影响, -->
<!-- 因为消息会在broker的内存中大量堆积,由于开启了producer-flow-control,-->
<!-- 将导致所有的生产者生产消息的速度放慢,这样即使某些消费消息速度非常 -->
<!-- 快的消费者也将放慢其消费消息的速度 -->
<!-- 为此增加了以下几种策略控制 -->
<!-- broker为该主题最多保存1000条消息,如果消息数目超过了1000, -->
<!-- 旧消息将被丢弃 -->
<pendingMessageLimitStrategy>
<constantPendingMessageLimitStrategy limit="1000"/>
</pendingMessageLimitStrategy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
生产者流控制(producer-flow-control)配置:
如果broker占用的内存或硬盘空间到达配置值,broker会阻塞消息生产者的send()方法,直到一些消息被消费,broker才能够继续接收新消息并使用被消费消息所占用的内存或硬盘空间存放新的消息
<systemUsage>
<!-- broker一直没有可使用空间将有可能导致消息生产者的send()方法无限阻塞 -->
<!-- 一种替代方式是使用下面的配置,这时send()方法将会失败并抛出一个 -->
<!-- javax.jms.ResourceAllocationException异常 -->
<!-- <systemUsage sendFailIfNoSpace="true"> -->
<!-- 更好的解决方式如下,客户端会首先等待3000毫秒,然后再次尝试 -->
<!-- 如果此时broker依然没有足够的空间可用,才抛出异常 -->
<systemUsage sendFailIfNoSpaceAfterTimeout="3000">
<!-- 非持久化消息最大占用内存大小 -->
<memoryUsage>
<memoryUsage percentOfJvmHeap="70" />
</memoryUsage>
<!-- 持久化消息最大占用硬盘大小 -->
<storeUsage>
<storeUsage limit="100 gb"/>
</storeUsage>
<!-- 临时消息最大占用硬盘大小 -->
<tempUsage>
<tempUsage limit="50 gb"/>
</tempUsage>
</systemUsage>
</systemUsage>
去掉非必需的通信协议(Client与Broker、Broker与Broker之间使用该协议进行通信),只留下TCP协议(特别需要注意的是61616是broker的监听端口):
<transportConnectors>
<!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
<transportConnector name="tcp" uri="tcp://0.0.0.0:61616
?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<!--
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672
?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:61613
?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883
?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:61614
?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
-->
</transportConnectors>
2,web服务配置:
$ACTIVEMQ_HOME/conf/activemq.xml文件的最后引入了jetty.xml文件:
<import resource="jetty.xml"/>
ActiveMQ中内置了一个servlet引擎(参见$ACTIVEMQ_HOME/conf/jetty.xml,角色权限、校验规则等配置都在该文件中,这里不详细说明了),用以提供web监控服务,默认的端口号是8161:
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
<!-- the default port number for the web console -->
<property name="port" value="8161"/>
</bean>
web服务需要登录后才能使用,账号信息保存在$ACTIVEMQ_HOME/conf/jetty-realm.properties文件中:
<bean id="securityLoginService" class="org.eclipse.jetty.security.HashLoginService">
<property name="name" value="ActiveMQRealm" />
<property name="config" value="${activemq.conf}/jetty-realm.properties" />
</bean>
$ACTIVEMQ_HOME/conf/jetty-realm.properties中的账号、账号密码和账号角色信息如下:
# Defines users that can access the web (console, demo, etc.)
# username: password [,rolename ...]
admin: admin, admin
user: user, user
3,日志配置:
[hadoop@fedora1 bin]$ vi ../conf/log4j.properties
ActiveMQ的日志文件存放路径如下:
log4j.appender.logfile.file=${activemq.base}/data/activemq.log
......
log4j.appender.logfile.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n
四,启动ActiveMQ
[hadoop@fedora1 bin]$ nohup ./activemq start &
[hadoop@fedora1 bin]$ cat nohup.out
INFO: Using default configuration
(you can configure options in one of these file: /etc/default/activemq /home/fedora1/.activemqrc)
INFO: Invoke the following command to create a configuration file
./activemq setup [ /etc/default/activemq | /home/fedora1/.activemqrc ]
INFO: Using java '/home/hadoop/jdk1.6.0_45/bin/java'
INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details
INFO: pidfile created : '/home/hadoop/apache-activemq-5.9.1/data/activemq-fedora1.pid' (pid '14196')
通过ps -ef | grep activemq命令可以看到ActiveMQ的进程号是14196
查看日志文件
[hadoop@fedora1 bin]$ cat ../data/activemq.log
日志中有如下信息说明ActiveMQ启动成功:
2014-07-22 15:33:03,268 | INFO
| Apache ActiveMQ 5.9.1 (localhost, ID:fedora1-50989-1406032419556-0:1) started
| org.apache.activemq.broker.BrokerService | main
还能够看到很多其它重要信息:
2014-07-22 15:33:03,267 | INFO
| Listening for connections at: tcp://fedora1:61616?maximumConnections=1000
&wireFormat.maxFrameSize=104857600
| org.apache.activemq.transport.TransportServerThreadSupport | main
2014-07-22 15:33:03,802 | INFO
| ActiveMQ WebConsole available at http://localhost:8161/
| org.apache.activemq.web.WebConsoleStarter | main
[hadoop@fedora1 bin]$ netstat -an|grep 61616
tcp 0 0 :::61616 :::* LISTEN
[hadoop@fedora1 bin]$ netstat -an|grep 8161
tcp 0 0 :::8161 :::* LISTEN
ActiveMQ启动后,可以通过Web服务查看其状态,账号密码为admin/admin:
五,简单测试
消息生产者:
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class MessageSender {
private static String URL = "tcp://localhost:61616";
private static String QUEUE_NAME = "test_queue";
public static void main(String[] args) {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(URL);
Connection conn = null;
Session sess = null;
try {
conn = factory.createConnection();
conn.start();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = sess.createQueue(QUEUE_NAME);
MessageProducer producer = sess.createProducer(dest);
TextMessage msg = sess.createTextMessage("Just a test!");
producer.send(msg);
} catch (JMSException e) {
e.printStackTrace();
} finally {
if(sess != null)
try {
sess.close();
} catch (JMSException e) {
e.printStackTrace();
}
if(conn != null)
try {
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
消息消费者,有两种实现方式:
1,Listener
import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionFactory;
public class IMessageListener implements MessageListener {
private static String URL = "tcp://localhost:61616";
private static String QUEUE_NAME = "test_queue";
public void onMessage(Message msg) {
if(null != msg && msg instanceof TextMessage){
try {
System.out.println("Message : " + ((TextMessage)msg).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args){
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(URL);
Connection conn = null;
Session sess = null;
try {
conn = factory.createConnection();
conn.start();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = sess.createQueue(QUEUE_NAME);
MessageConsumer consumer = sess.createConsumer(dest);
consumer.setMessageListener(new IMessageListener());
} catch (JMSException e) {
e.printStackTrace();
} /*finally { // 连接关闭就没有consumer了
if(sess != null)
try {
sess.close();
} catch (JMSException e) {
e.printStackTrace();
}
if(conn != null)
try {
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}*/
}
}
2,Receiver
import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionFactory;
public class IMessageReceiver {
private static String URL = "tcp://localhost:61616";
private static String QUEUE_NAME = "test_queue";
public static void main(String[] args){
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(URL);
Connection conn = null;
Session sess = null;
try {
conn = factory.createConnection();
conn.start();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = sess.createQueue(QUEUE_NAME);
MessageConsumer consumer = sess.createConsumer(dest);
while(true){
Message message = consumer.receive();
if(null != message && message instanceof TextMessage)
System.out.println("Message : " + ((TextMessage)message).getText());
}
} catch (JMSException e) {
e.printStackTrace();
} finally {
if(sess != null)
try {
sess.close();
} catch (JMSException e) {
e.printStackTrace();
}
if(conn != null)
try {
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
Message : Just a test!