Connection方法
在成功创建正确ConnectionFactory后,下一步将是创建一个连接,它是JMS定义的一个接口。ConnectionFactory负责返回可以与底层消息传递系统进行通信的Connection实现。通常客户端只使用单一连接。根据JMS文档,Connection的目的是“利用JMS提供者封装开放的连接”,以及表示“客户端与提供者服务例程之间的开放TCP/IP套接字”。该文档还指出Connection应该是进行客户端身份验证的地方等等。
当一个Connection被创建时,它默认是关闭的,必须使用start方法开启。一个Connection可以创建一个或多个Session。
当一个程序执行完成后,必须关闭之前创建的Connection,负责ActiveMQ不能释放资源,关闭一个Connection同样 也关闭了Session,MessageProducer和MessageConsumer
Connection creatConnection();
Connection creatConnection(String userName,String password);
Session方法使用
一旦从ConnectionFactory中获得一个Connection,必须从Connection中创建一个或者多Session。Session是一个发送或者接收消息的线程,可以使用Session创建MessageProducer,MessageConsumer和Message。
Session可以被事务化,也可以不被事务化,通常。可以通过想Connection上适当创建方法传递一个布尔参数对此进行设置。
Session creatSession(boolean transacted,int acknowledgeMode);其中transacted为使用事务标识,acknowledgeMode签收模式。
结束事务有两种方法:提交或者回滚。当一个事物提交,消息被处理。如果事务中有一个步骤失败,事务就会滚,这个事务中的已经执行的动作将被撤销。再发送消息最后也必须要使用session.commit()方法标识提交事务。
签收模式有三种形式:
自动签收
Session.AUTO_ACKNOWLEDGE当客户端从receive或者onMessage成功返回时,Session自动签收客户端的这条消息的收条。
在Consumer端手动去掉用acknowledge方法给消息中间件一个反馈
Session.CLIENT_ACKNOWLEDGE 客户端通过调用消息(Message)的acknowledge方法签收消息。在这种情况下,签收发生在Session层面:签收一个已消费的消息会自动地签收这个Session所有已消费消息的收条。
栗子:
package com;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Receiver {
public static void main(String[] args) throws JMSException {
//第一步 建立ConnectionFactory工厂对象,需要填入用户名和密码以及要链接的地址,
//均使用默认即可,默认端口为"tcp://localhost:61616"
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("xxx", "xxx", "tcp://localhost:61616");
//第二步 通过ConnerctionFactory工厂对象我们创建一个Connection链接,并且调用
//Connection的start方法开启链接,Connection默认是关闭的。
Connection connection = connectionFactory.createConnection();
connection.start();
//第三步 通过Connection对象创建Session会话(上下文环境对象),用于接受消息,参数配置1为
//是否启动事务,参数配置2位签收模式,一般我们设置自动签收。
Session session = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);
//第四步 、通过Session创建Destionation对象,指的是一个客户端用来指定生产消息目标和消费消息来源
//的对象,在PTP模式中,Destination被称作Queue即队列;在Pub/Sub模式,Destination被称作Topic即主题。
//在程序中可以使用多个Queue和Topic.
Destination destination = session.createQueue("queue1");
//第五步 我们需要通过Session对象创建消息的发送和接收对象(生产者和消费者)MessageProducer/MessageConsumer.
MessageConsumer messageConsumer = session.createConsumer(destination);
while(true){
TextMessage textMessage = (TextMessage) messageConsumer.receive();
//手工去签收消息,另起一个线程(TCP)去通知我们的MQ服务,确认签收。
textMessage.acknowledge();
if(textMessage==null){
break;
}
System.out.println("收到的内容: "+textMessage.getText() );
}
if(connection !=null){
connection.close();
}
}
}
基于从消息队列中拿到数据后返回给Consumer端后Consumer确认收到消息再给消息中间件一个反馈信息
Sessage.DUPS_OK_ACKNOWLEDGE 此选项指示Session不必确保对传送消息的签收。他可能引起消息的重复,但是降低了Session的开销,所以只有对客户端能容忍重复的消息,才可使用。
例如 :
P为生产者
中间的为消息队列服务器
C为消费者
生产者发送一条消息给消息队列,假设为Q1,然后消费者去从消息队列中去取Q1这个消息,返回给消费者,然后消费者又给消息队列返回一个消费成功的这么一个信号,无需我们去关心那个消费后然后给消息中间件反馈信息的那一步操作。调用第二种则是必须要在Consumer端手动去掉用acknowledge方法,消息中间件才认为你这个消息被消费了。要不会一直在消息队列中,即使你已经运行了Consumer端(没有手动调用acknowledge方法)。
MessageProducer
MessageProducer:是一个由Session创建的对象,用来向Destination发送消息。
Void send(Destination destination,Message message);
Void send(Destination destination,Message message,int deliveryMode,int priority,long timeToLive);
Void send(Message message);
Void send(Destination destination,Message message,,int priority,long timeToLive);
其中deliveryMode为传送模式,priority为消息优先级,timeToLive微消息过期时间。
ActiveMQ支持两种消息传送模式:PERSISTENT和NON_PERSISTENT两种。如果不指定传送模式,那么默认是持久性消息。如果容忍消息丢失,那么使用非持久性消息可以改善性能和减少存储的开销。
消息优先级从0-9十个级别,0-4是普通消息,5-9是加急消息。如果不指定优先级,则默认为4。JMS不要求按照这是个优先级发送消息,但必须保证加息消息优于普通消息到达。
默认情况下,消息永不会过期。如果消息在特定周期失去意义,那么可以设置过期时间,时间单位为毫秒。
栗子:
package com;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
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 Sender {
public static void main(String[] args) throws JMSException {
//第一步 建立ConnectionFactory工厂对象,需要填入用户名和密码以及要链接的地址,
//均使用默认即可,默认端口为"tcp://localhost:61616"
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("xxx", "xxx", "tcp://localhost:61616");
//第二步 通过ConnerctionFactory工厂对象我们创建一个Connection链接,并且调用
//Connection的start方法开启链接,Connection默认是关闭的。
Connection connection = connectionFactory.createConnection();
connection.start();
//第三步 通过Connection对象创建Session会话(上下文环境对象),用于接受消息,参数配置1为
//是否启动事务,参数配置2为签收模式,一般我们设置自动签收。
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//第四步 、通过Session创建Destionation对象,指的是一个客户端用来指定生产消息目标和消费消息来源
//的对象,在PTP模式中,Destination被称作Queue即队列;在Pub/Sub模式,Destination被称作Topic即主题。
//在程序中可以使用多个Queue和Topic.
Destination destination = session.createQueue("queue1");
//第五步 我们需要通过Session对象创建消息的发送和接收对象(生产者和消费者)MessageProducer/MessageConsumer.
MessageProducer messageProducer = session.createProducer(null);
//第六步 我们可以使用MessageProducer的serDeliveryMode方法为其设置持久化特性和非持久化特性
//(DeliveryMode)。
//messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//第七步 最后我们使用JMS规范TextMessage形式创建数据(通过Session对象),并用MessageProducer的send方法发送数据。同理客户端使用receive方法进行接收数据。
//最后不要忘记关闭Connection.
//发布五条信息到mq中
for (int i = 1; i <= 5; i++) {
TextMessage textMessage = session.createTextMessage();
textMessage.setText("我是消息内容"+i);
/**
* 第一个参数 目的地
* 第二个参数 消息
* 第三个参数 是否持久化
* 第四个参数 优先级(0-9 ,0-4表示普通,5-9表示加急,一般默认为4。不一定按照优先级的顺序去执行。假设有一万条消息,加急的会比普通的比例多一些,并不是加了急就一定会先执行加急的。)
* 第五个参数 消息在MQ上的存放有效期(设置了有效期,如果过了有效期没有被消费,那么这个消息在MQ就不存在了。)
* */
messageProducer.send(destination, textMessage, DeliveryMode.NON_PERSISTENT, i, i * 1000 * 60);
}
//上面得session 设置为true 这里是使用事务进行提交。
session.commit();
if(connection !=null){
connection.close();
}
}
}
MessageConsumer(一)
MessageConsumer是一个由Session创建的对象,用来从Destination接收消息。
MessageConsumer creatConsumer(Destination destination);
MessageConsumer creatConsumer(Destination destination,String messageSelector);
MessageConsumer creatConsumer(Destination destination,String messageSelector,boolean noLocal);
TopicSubscriber creatDurableSubscriber(Topic topic,String name);
TopicSubscriber creatDurableSubscriber(Topic topic,String name,String messageSelector,boolean noLocal);
其中messageSelector为消息选择器;noLocal标志默认为false,当设置为true时限制消费者只能接收和自己相同的连接所发布的消息,此标志只适用于主题,不适用于队列;name标识订阅主题所对应的的订阅名称,持久订阅时需要设置此参数。
Public final String SELECTOR = “JMS_TYPE = ‘MY_TAG1’”;该选择器检查了传入消息的JMS_TYPE属性,并确定了这个属性的值是否等于MY_TAG1。如果想等,则消息被消费;如果不想等,那么消息会被忽略。
Consumer端会进行过滤筛选,其实就是String类的字符串。MQ把消息放到了kahadb上,看不到摸不着,非想看的话就连接mysql数据或者别的数据库。
找到activeMQ.xml
添加
dataSource后面的是ID
然后在添加以上标签,然后再去activeMQ文件夹的lib文件中添加mysq连接驱动包,然后重启activeMQ。此时会多出三个表。
MessageConsumer(二)
消息的同步和异步接收:
消息的同步接收是指客户端主动去接受消息,客户端可以采用MessageConsumer的receive方法去接收下一个消息。
Message receive();
Message receive(long timeout);
Message receiveNoWait();
消息的异步接收是指当消息到达时,ActiveMQ主动通知客户端,可以通过注册一个实现MessageListener接口的对象到MessageConsumer。messageLinstener只有一个必须实现的方法----onMessage,它只接收一个参数,即Message。在为每个发送到Destination的消息实现OonMessage时,将调用该参数。
栗子:
Producer.java
package com;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Producer {
//单例模式
//1 连接工厂
private ConnectionFactory connectionFactory;
//2 连接对象
private Connection connection;
//3 Session对象
private Session session;
//4 生产者
private MessageProducer messageProducer;
public Producer(){
try {
this.connectionFactory = new ActiveMQConnectionFactory("xxx","xxx","tcp://localhost: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 (Exception e) {
e.printStackTrace();
}
}
public Session getsession(){
return this.session;
}
public void send1(/*String QueueName,Message message*/){
try {
Destination destination = this.session.createQueue("first");
MapMessage msg1 = this.session.createMapMessage();
msg1.setString("name", "zhangsan");
msg1.setString("age", "23");
//设置属性 消费者端会根据设置的属性进行消息筛选。
msg1.setStringProperty("color", "blue");
msg1.setIntProperty("sal", 2200);
MapMessage msg2 = this.session.createMapMessage();
msg2.setString("name", "lisi");
msg2.setString("age", "26");
//设置属性 消费者端会根据设置的属性进行消息筛选。
msg2.setStringProperty("color", "red");
msg2.setIntProperty("sal", 1300);
MapMessage msg3 = this.session.createMapMessage();
msg3.setString("name", "wangwu");
msg3.setString("age", "28");
//设置属性 消费者端会根据设置的属性进行消息筛选。
msg3.setStringProperty("color", "green");
msg3.setIntProperty("sal", 1500);
//设定三个messageProducer中的send方法发送到destination目的地去。
this.messageProducer.send(destination, msg1, DeliveryMode.NON_PERSISTENT, 2,1 * 1000 * 60L);
this.messageProducer.send(destination, msg2, DeliveryMode.NON_PERSISTENT, 3,1 * 1000 * 60L);
this.messageProducer.send(destination, msg3, DeliveryMode.NON_PERSISTENT, 5,1 * 1000 * 60L);
} catch (Exception e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
Producer p = new Producer();
p.send1();
}
}
Consumer.java
package com;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.memory.list.MessageList;
public class Consumer {
public final String SELECTOR_1 = "color = 'blue'";
public final String SELECTOR_2 = "color = 'blue' AND sal > 2000";
public final String SELECTOR_3 = "color = 'blue' AND sal > 2000";
//1 连接工厂
private ConnectionFactory connectionFactory;
//2 连接对象
private Connection connection;
//3 Session对象
private Session session;
//4 消费者
private MessageConsumer messageConsumer;
//5 目标地址
private Destination destination;
public Consumer_shaixuanzijixiangyaode(){
try {
this.connectionFactory = new ActiveMQConnectionFactory("bhz","bhz","tcp://localhost:61616");
this.connection = this.connectionFactory.createConnection();
this.connection.start();
this.session = this.connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);
this.destination = this.session.createQueue("first");
//创建消费者的时候发生了变化
this.messageConsumer = this.session.createConsumer(this.destination,SELECTOR_1);
} catch (Exception e) {
e.printStackTrace();
}
}
public void receiver(){
try {
this.messageConsumer.setMessageListener(new Listener());
} catch (Exception e) {
// TODO: handle exception
}
}
class Listener implements MessageListener{
public void onMessage(Message message){
try {
if(message instanceof TextMessage){
}
if(message instanceof MapMessage){
MapMessage mapMessage = (MapMessage) message;
System.out.println(mapMessage.toString());
System.out.println(mapMessage.getString("name"));
System.out.println(mapMessage.getString("age"));
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
public static void main(String[] args) {
Consumer_shaixuanzijixiangyaode consumer = new Consumer_shaixuanzijixiangyaode();
consumer.receiver();
}
}
选择器选择:this.messageConsumer = this.session.createConsumer(this.destination,SELECTOR_1);
Message
JMS程序的最终是生产和消费的消息能被其他程序使用,JMS的Message是一个既简单有不乏灵活性的基本格式,允许创建不同平台上符合非JMS程序格式的消息。Message由以下几部分组成:消息头,属性和消息体。
BlobMessage creatBlobMessage(File file);
BlobMessage creatBlobMessage(InputStream in);
BlobMessage creatBlobMessage(URL url);
BlobMessage creatBlobMessage(URL url,boolean deletedByBroker);
BlobMessage creatBlobMessage();
MapMessage creatMessage();
Message creatMessage();
ObjcetMessage creatObjectMessage();
ObjcetMessage creatObjectMessage(Serializable object);
TextMessage creatTextMessage();
TextMessage creatTextMessage(String text);
我们一般会在接收端通过instanceof方法去区别数据类型。
创建临时消息
ActiveMQ通过creatTemporaryQueue和creatTemporaryTopic创建临时目标,这些目标持续到创建它的Connection关闭。只有创建临时目标的Connection所创建的客户端才可以从临时目标中接收消息,但是任何的生产这都可以向临时的目标发送消息。如果关闭了创建此目标的Connection,那么临时目标被关闭,内容也将消失。
TemproaryQueue creatTemproaryQueue();
TemproaryTopic creatTemproaryTopic();