我们写一个简单的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链接。
<dependency> <groupId>org.apache.activemqgroupId> <artifactId>activemq-allartifactId> <version>5.11.1version> dependency>
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服务器:
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条消息
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中配置
其次,因为每个消息都是长时间的操作,一定要等消息里的命令完全执行完毕后,再向ActiveMQ发送ACK,这样就可以保证所有的消息都是按照优先级来消费的。
消息的同步接收是指:客户端主动去接收消息,客户端课采用MessageConsume的receive方法去接收下一个消息。
消息的异步接收是指:当消息到达MQ服务器时,MQ服务器主动通知客户端,客户点通过注册一个实现MessageListener接口的对象到MessageConsumer。MessageListener只有一个必须实现的方法:onMessage,它只接受一个参数Message。在为每个发送到Destination的消息实现onMessage时,调用该方法。
示例:参考下一节消息过滤的内容。
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
发布订阅模式有点类似于我们日常生活中订阅报纸。每年到年尾的时候,邮局就会发一本报纸集合让我们来选择订阅哪一个,在这个表里头列了所有出版发行的报纸,那么对于我们每一个订阅者来说,我们可以选择一份或者多份报纸。比如北京日报、潇湘晨报等。那么这些个我们订阅的报纸就相当于发布订阅模式里的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(); } } }