我们写一个简单的Hello World实例,让大家感受下ActiveMQ,需要完成发送者和接受者两部分代码的编写。
(1)建立ConnectionFactory工厂对象,需要填入用户名、密码以及要连接的地址,均使用默认即可,默认端口为:tcp://10.0.31.144:61616
(2)通过ConnectionFactory工厂对象创建一个Connection链接,并且调用ConnectionFactory的start方法开启链接,Connection默认是关闭的。
(3)通过Connection对象创建session会话,用于接收消息,参数配置1:是否启用事务,蚕食配置2:签收模式,一般我们设置为自动签收。
签收模式有三种:
Session.AUTO_ACKNOWLEDGE 当客户端从receive或onMessage成功返回时,Session自动签收客户端的这条消息的收条。
Session.CLIENT_ACKNOWLEDGE 客户端通过调用消息(Message)的acknowledge方法签收消息,在这种情况下,签收发生在Session层面:签收一个已消费的消息,会自动的签收这个Session所有已消费的消息的收条。
Session.DUPS_OK_ACKNOWLEDGE 此选项指示Session不必确保对传送消息的签收,他可能引起消息的重复,但是降低了Session的开销,所以之后客户端能容忍接收重复消息时,才可以使用。
(4)通过session创建Destination对象,指的是一个客户端用来指定生产的消息目标或消息来源的对象。在PTP模式中,Destination被称作Queue队列,在Pub/Sub模式中Destination被称作topic主题。在程序中可以使用多个Queue或topic。
(5)我们需要通过session对象创建消息的发送和接受对象MessageProducer和MessageCustomer.
(6)我们可以使用MessageProducer的setDeliverryMode方法设置持久化特性和费持久化特性(DeliverryMode)。
(7)我们使用JMS规范的TextMessage形式创建数据(通过Session对象),并用MessageProducer的send方法发送数据或MessageCustomer的receive方法接收数据。
(8)最后不要忘记关闭Connection链接。
1 工程搭建Maven依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.11.1</version>
</dependency>
2 消息发送者
Sender.java
public class Sender {
public static void main(String[] args) throws Exception{
//(1)建立ConnectionFactory工厂对象,需要填入用户名、密码以及要连接的地址,均使用默认即可,默认端口为:tcp://10.0.31.144:61616
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("chen","chen123","tcp://10.0.31.144:61616");
//(2)通过ConnectionFactory工厂对象创建一个Connection链接,并且调用ConnectionFactory的start方法开启链接,Connection默认是关闭的。
Connection connection = connectionFactory.createConnection();
connection.start();
//(3)通过Connection对象创建session会话,用于接收消息,参数配置1:是否启用事务,蚕食配置2:签收模式,一般我们设置为自动签收。
Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//(4)通过session创建Destination对象,指的是一个客户端用来指定生产的消息目标或消息来源的对象。在PTP模式中,Destination被称作Queue队列,在Pub/Sub模式中Destination被称作topic主题。在程序中可以使用多个Queue或topic。
Destination destination = session.createQueue("helloworld");//创建一个queue的消息目标
//(5)我们需要通过session对象创建消息的发送和接受对象MessageProducer和MessageCustomer.
MessageProducer messageProducer = session.createProducer(destination);
//(6)我们可以使用MessageProducer的setDeliverryMode方法设置持久化特性和费持久化特性(DeliverryMode)。
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); //非持久化,下次再开启mq时,数据就不存在了
//(7)我们使用JMS规范的TextMessage形式创建数据(通过Session对象),并用MessageProducer的sen发送数据或MessageCustomer的receive方法接收数据。
for(int i=1;i<=10;i++){
TextMessage textMessage = session.createTextMessage("我是消息内容"+i);
messageProducer.send(textMessage);
}
//(8)最后不要忘记关闭Connection链接。
if(null != connection){
connection.close();
}
}
}
运行后观察MQ服务器:
3 消息接受者
Client.java
public class Client {
public static void main(String[] args) throws Exception{
//(1)建立ConnectionFactory工厂对象,需要填入用户名、密码以及要连接的地址,均使用默认即可,默认端口为:tcp://10.0.31.144:61616
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("chen","chen123","tcp://10.0.31.144:61616");
//(2)通过ConnectionFactory工厂对象创建一个Connection链接,并且调用ConnectionFactory的start方法开启链接,Connection默认是关闭的。
Connection connection = connectionFactory.createConnection();
connection.start();
//(3)通过Connection对象创建session会话,用于接收消息,参数配置1:是否启用事务,蚕食配置2:签收模式,一般我们设置为自动签收。
Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//(4)通过session创建Destination对象,指的是一个客户端用来指定生产的消息目标或消息来源的对象。在PTP模式中,Destination被称作Queue队列,在Pub/Sub模式中Destination被称作topic主题。在程序中可以使用多个Queue或topic。
Destination destination = session.createQueue("helloworld");//创建一个queue的消息目标
//(5)我们需要通过session对象创建消息的发送和接受对象MessageProducer和MessageCustomer.
MessageConsumer messageConsumer = session.createConsumer(destination);
//(7)我们使用JMS规范的TextMessage形式创建数据(通过Session对象),并用MessageProducer的sen发送数据或MessageCustomer的receive方法接收数据。
while (true){
TextMessage msg = (TextMessage) messageConsumer.receive();
if(null == msg) break;
System.out.println("客户端收到消息:"+msg.getText());
}
//(8)最后不要忘记关闭Connection链接。
if(null != connection){
connection.close();
}
}
}
运行观察控制台输出:
客户端收到消息:我是消息内容1 客户端收到消息:我是消息内容2 客户端收到消息:我是消息内容3 客户端收到消息:我是消息内容4 客户端收到消息:我是消息内容5 客户端收到消息:我是消息内容6 客户端收到消息:我是消息内容7 客户端收到消息:我是消息内容8 客户端收到消息:我是消息内容9 客户端收到消息:我是消息内容10
观察Mq服务器:
解释:有一个消费端,消费了hellworld 10条消息
4 消息优先级
MessageProducer的send方法提供了多个参数配置,
send(Destination,Message,int deliveryMode,int priority,long timeToLive):
deliveryMode:传送模式,PERSISTENT(默认)和NON_PERSISTENT,如果容忍消息丢失,可以使用NON_PERSISTENT。
priority:消息优先级,从0-9十个级别,0-4是普通消息,5-9是加急消息,默认是4。
timeToLive:消息过期时间,默认情况下消息永不过期。
要使用ActiveMQ的消息优先级,
首先,在activemq.xml中配置
<policyEntry queue=">" producerFlowControl="false" prioritizedMessages="true" useCache="false" expireMessagesPeriod="0" queuePrefetch="1" />
其次,因为每个消息都是长时间的操作,一定要等消息里的命令完全执行完毕后,再向ActiveMQ发送ACK,这样就可以保证所有的消息都是按照优先级来消费的。
5 消息的同步和异步接收
消息的同步接收是指:客户端主动去接收消息,客户端课采用MessageConsume的receive方法去接收下一个消息。
消息的异步接收是指:当消息到达MQ服务器时,MQ服务器主动通知客户端,客户点通过注册一个实现MessageListener接口的对象到MessageConsumer。MessageListener只有一个必须实现的方法:onMessage,它只接受一个参数Message。在为每个发送到Destination的消息实现onMessage时,调用该方法。
示例:参考下一节消息过滤的内容。
6 消息过滤
MessageConsumer是一个由Session创建的对象,用来从Destination接收消息。
session.createConsumer(Destination destination); session.createConsumer(Destination destination,String messageSelector); session.createConsumer(Destination destination,String messageSelector,boolean noLocal); session.createDurableSubscriber(Topic topic,String name); session.createDurableSubscriber(Topic topic,String name,boolean noLocal);
其中messageSelector为消息选择器,noLocal标志默认为false,设置为true时,限制消费者只能接受和自己相同连接(connection)所发布的消息,此标志只适用于topic主题模式,不适用于queue队列模式;name标识订阅topic主题所对应的订阅名称,持久订阅时需要设置此参数。
举例:
public final String SELECTOR = "JMS_TYPE='value'";
该选择器检查了传入消息的“JMS_TYPE”属性,并确定了这个属性的值是否等于“value”。如果相等,则消息被消费,如果不相等,那么消息会被忽略。
代码示例:
消息发送者:Sender.java
public class Sender {
private ConnectionFactory connectionFactory;
private Connection connection;
private Session session;
private MessageProducer messageProducer;
public Sender() {
try{
this.connectionFactory = new ActiveMQConnectionFactory("chen",
"chen123",
"tcp://10.0.31.144:61616");
this.connection = this.connectionFactory.createConnection();
this.connection.start();
this.session = this.connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);
this.messageProducer=this.session.createProducer(null);
}catch (JMSException e){
e.printStackTrace();
}
}
public void send() {
try{
Destination destination = this.session.createQueue("first");
MapMessage msg1 = this.session.createMapMessage();
msg1.setString("name","Jack");
msg1.setString("address","Bei Jing");
msg1.setIntProperty("age",23);
msg1.setStringProperty("sex","m");
MapMessage msg2 = this.session.createMapMessage();
msg2.setString("name","rose");
msg2.setString("address","Nan Jing");
msg2.setIntProperty("age",22);
msg2.setStringProperty("sex","f");
MapMessage msg3 = this.session.createMapMessage();
msg3.setString("name","Tom");
msg3.setString("address","Tian Jin");
msg3.setIntProperty("age",23);
msg3.setStringProperty("sex","m");
MapMessage msg4 = this.session.createMapMessage();
msg4.setString("name","Lily");
msg4.setString("address","Qing dao");
msg4.setIntProperty("age",21);
msg4.setStringProperty("sex","f");
this.messageProducer.send(destination,msg1,DeliveryMode.NON_PERSISTENT,1,1000*60*60);
this.messageProducer.send(destination,msg2,DeliveryMode.NON_PERSISTENT,3,1000*60*60);
this.messageProducer.send(destination,msg3,DeliveryMode.NON_PERSISTENT,5,1000*60*60);
this.messageProducer.send(destination,msg4,DeliveryMode.NON_PERSISTENT,7,1000*60*60);
this.connection.close();
}catch (JMSException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Sender sender = new Sender();
sender.send();
}
}
运行send()方法向mq服务器发送4条数据;
消息接收者:Client.java
public class Client {
//使用selector的属性,必须是由setXXXProperty()方法定义的属性.
public final String SELECTOR_1 = "name LIKE 'T%'";//无效
public final String SELECTOR_2 = "age >= 22";
public final String SELECTOR_3 = "sex='f'";
private ConnectionFactory connectionFactory;
private Connection connection;
private Session session;
private Destination destination;
private MessageConsumer messageConsumer;
public Client() {
try{
this.connectionFactory = new ActiveMQConnectionFactory("chen",
"chen123",
"tcp://10.0.31.144:61616");
this.connection = this.connectionFactory.createConnection();
this.connection.start();
this.session = this.connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);
//定义destination
this.destination=this.session.createQueue("first");
//创建消费者的时候发生了变化
this.messageConsumer=this.session.createConsumer(this.destination,SELECTOR_2);
}catch (JMSException e){
e.printStackTrace();
}
}
public void receiver(){
try{
this.messageConsumer.setMessageListener(new Listener());
}catch (JMSException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Client c = new Client();
c.receiver();
}
}
其中Listener.java:
public class Listener implements MessageListener{
public void onMessage(Message message) {
try {
if(message instanceof MapMessage){
MapMessage msg = (MapMessage) message;
System.out.println(msg.toString());
System.out.println(msg.getString("name"));
System.out.println(msg.getString("address"));
System.out.println(msg.getInt("age"));
System.out.println(msg.getString("sex"));
}else{
System.out.println("消息源类型错误!");
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
运行client.receive()方法,观察输出结果:
ActiveMQMapMessage {commandId = 5, responseRequired = false, messageId = ID:localhost-51630-1508748356821-1:1:1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:localhost-51630-1508748356821-1:1:1:1, destination = queue://first, transactionId = null, expiration = 1508751957013, timestamp = 1508748357013, arrival = 0, brokerInTime = 1508748322576, brokerOutTime = 1508748334499, correlationId = null, replyTo = null, persistent = false, type = null, priority = 1, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@6fecb8f3, marshalledProperties = org.apache.activemq.util.ByteSequence@5a725e7, dataStructure = null, redeliveryCounter = 0, size = 0, properties = {age=23, sex=m}, readOnlyProperties = true, readOnlyBody = true, droppable = false, jmsXGroupFirstForConsumer = false} ActiveMQMapMessage{ theTable = {} } Jack Bei Jing 23 m ActiveMQMapMessage {commandId = 6, responseRequired = false, messageId = ID:localhost-51630-1508748356821-1:1:1:1:2, originalDestination = null, originalTransactionId = null, producerId = ID:localhost-51630-1508748356821-1:1:1:1, destination = queue://first, transactionId = null, expiration = 1508751957014, timestamp = 1508748357014, arrival = 0, brokerInTime = 1508748322578, brokerOutTime = 1508748334505, correlationId = null, replyTo = null, persistent = false, type = null, priority = 3, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@2e6bf465, marshalledProperties = org.apache.activemq.util.ByteSequence@39220730, dataStructure = null, redeliveryCounter = 0, size = 0, properties = {age=22, sex=f}, readOnlyProperties = true, readOnlyBody = true, droppable = false, jmsXGroupFirstForConsumer = false} ActiveMQMapMessage{ theTable = {} } rose Nan Jing 22 f ActiveMQMapMessage {commandId = 7, responseRequired = false, messageId = ID:localhost-51630-1508748356821-1:1:1:1:3, originalDestination = null, originalTransactionId = null, producerId = ID:localhost-51630-1508748356821-1:1:1:1, destination = queue://first, transactionId = null, expiration = 1508751957015, timestamp = 1508748357015, arrival = 0, brokerInTime = 1508748322578, brokerOutTime = 1508748334505, correlationId = null, replyTo = null, persistent = false, type = null, priority = 5, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@70f0263d, marshalledProperties = org.apache.activemq.util.ByteSequence@5bfb2303, dataStructure = null, redeliveryCounter = 0, size = 0, properties = {age=23, sex=m}, readOnlyProperties = true, readOnlyBody = true, droppable = false, jmsXGroupFirstForConsumer = false} ActiveMQMapMessage{ theTable = {} } Tom Tian Jin 23 m
7 Pub/Sub模式
发布订阅模式有点类似于我们日常生活中订阅报纸。每年到年尾的时候,邮局就会发一本报纸集合让我们来选择订阅哪一个,在这个表里头列了所有出版发行的报纸,那么对于我们每一个订阅者来说,我们可以选择一份或者多份报纸。比如北京日报、潇湘晨报等。那么这些个我们订阅的报纸就相当于发布订阅模式里的topic。有很多个人订阅报纸,也有人可能订阅了和我相同的报纸。那么在这里相当于我们在同一个topic里面注册了。对于一份报纸发行来说,它和所有的订阅者就构成了一个1对多的关系,这种关系如下所示:
代码样例:
消息发布者Sender.java
public class Sender {
private ConnectionFactory connectionFactory;
private Connection connection;
private Session session;
private MessageProducer messageProducer;
public Sender() {
try{
this.connectionFactory = new ActiveMQConnectionFactory("chen",
"chen123",
"tcp://10.0.31.144:61616");
this.connection = this.connectionFactory.createConnection();
this.connection.start();
this.session = this.connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);
this.messageProducer=this.session.createProducer(null);
}catch (JMSException e){
e.printStackTrace();
}
}
public void sendMessage() {
try{
Destination destination = this.session.createTopic("topic");
TextMessage msg1 = this.session.createTextMessage("消息1");
TextMessage msg2 = this.session.createTextMessage("消息2");
TextMessage msg3 = this.session.createTextMessage("消息3");
this.messageProducer.send(destination,msg1);
this.messageProducer.send(destination,msg2);
this.messageProducer.send(destination,msg3);
this.connection.close();
}catch (JMSException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Sender sender = new Sender();
sender.sendMessage();
}
}
运行main方法查看Mq服务器上的内容:
消息订阅者:(创建多个Client,同时运行)
public class Client {
private ConnectionFactory connectionFactory;
private Connection connection;
private Session session;
private Destination destination;
private MessageConsumer messageConsumer;
public Client() {
try{
this.connectionFactory = new ActiveMQConnectionFactory("chen",
"chen123",
"tcp://10.0.31.144:61616");
this.connection = this.connectionFactory.createConnection();
this.connection.start();
this.session = this.connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);
//定义destination
this.destination=this.session.createTopic("topic");
//创建消费者的时候发生了变化
this.messageConsumer=this.session.createConsumer(this.destination);
}catch (JMSException e){
e.printStackTrace();
}
}
public void receiver(){
try{
this.messageConsumer.setMessageListener(new Listener());
}catch (JMSException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Client c = new Client();
c.receiver();
}
}
public class Listener implements MessageListener{
public void onMessage(Message message) {
try {
if(message instanceof TextMessage){
TextMessage msg = (TextMessage) message;
System.out.println(msg.toString());
System.out.println(msg.getText());
}else{
System.out.println("消息源类型错误!");
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}