activeMQ学习
ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。
1.JSM介绍
JMS(JavaMessage Service,java消息服务)使分布式通信耦合度更低,消息服务更加可靠以及异步性。JSM分为Point-to-Point(P2P)点对点模型和Publish/Subscribe(Pub/Sub)发布订阅模型。
1.1 p2p模式
每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
接收者在成功接收消息之后需向队列应答成功。
1.2 Pub/Sub模式
每个消息可以有多个消费者,针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。即使订阅者没有被激活(运行),它也能接收到发布者的消息。队列模型和PUB/SUB模型的区别,Queue只能由一个消费者接收,其他Queue中的成员无法接受到被已消费的信息,而Topic则可以,只要是订阅了Topic的消费者,全部可以获取到生产者发布的信息。
1.3 消息类型
JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据。
StreamMessage --Java原始值的数据流
MapMessage--一套名称-值对
TextMessage--一个字符串对象
ObjectMessage--一个序列化的 Java对象
BytesMessage--数据流信息
2. ActiveMQ
完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务), 对spring的支持。
2.1 下载安装
解压到计算机
双击启动ActiveMQ
访问http://127.0.0.1:8161/admin/ 就可以查看active管理后台了
初始账号密码 admin
依赖jar包
2.2 Queue测试
需求:一个生产者向一个消费者发送一个图片。
生产者:
public class QueueProducer {
private static String username = "admin";
private static String password = "admin";
private static String brokeurl = "tcp://127.0.0.1:61616";
public static void main(String[] args){
ConnectionFactoryconnectionFactory;
Connectionconnection = null;
Session session;
Destinationdestination;
MessageProducermessageProducer;
connectionFactory =new ActiveMQConnectionFactory(username, password, brokeurl);
try {
connection =connectionFactory.createConnection();
connection.start();
session =connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("activemq.queue");
messageProducer =session.createProducer(destination);
//发送一张图片
BytesMessagebytesMessage = session.createBytesMessage();
FileInputStreamfileInputStream = new FileInputStream(new File("E://timg.jpg"));
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
bytesMessage.writeBytes(bytes);
messageProducer.send(bytesMessage);
session.commit();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(connection != null){
try {
connection.close();
} catch (JMSException e){
e.printStackTrace();
}
}
}
}
}
结果
消费者:
public class QueueConsumer { private static String username = "admin"; private static String password = "admin"; private static String brokeurl = "tcp://127.0.0.1:61616"; private static String queuename = "activemq.queue"; public static void main(String[] args) throws IOException { ConnectionFactory connectionFactory; Connection connection; Session session; Destination destination; MessageConsumer messageConsumer; connectionFactory = new ActiveMQConnectionFactory(username,password,brokeurl); try { connection = connectionFactory.createConnection(); connection.start(); session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); destination = session.createQueue(queuename); messageConsumer = session.createConsumer(destination); BytesMessage bytesMessage = (BytesMessage) messageConsumer.receive(); byte[] bytes = new byte[(int) bytesMessage.getBodyLength()]; bytesMessage.readBytes(bytes); FileOutputStream fileOutputStream = new FileOutputStream(new File("E://111.jpg")); fileOutputStream.write(bytes); } catch (JMSException e) { e.printStackTrace(); } } }
成功获取图片。
2.3 pub/sub测试
生产者代码:
destination = session.createQueue("activemq.queue");
messageProducer = session.createProducer(destination);
修改为:
topic = session.createTopic(queuename); messageProducer = session.createProducer(topic);
测试结果:
Number Of Pending Messages 等待消费的消息这个是当前未出队列的数量。可以理解为总接收数-总出队列数
Messages Enqueued 进入队列的消息进入队列的总数量,包括出队列的。这个数量只增不减
Messages Dequeued 出了队列的消息可以理解为是消费掉的数量。
消费者:
public class TopicConsumer { private static String username = "admin"; private static String password = "admin"; private static String brokeurl = "tcp://127.0.0.1:61616"; private static String queuename = "activemq.topic"; public static void main(String[] args) throws Exception { ConnectionFactory connectionFactory; Connection connection; Session session; Topic topic; MessageConsumer messageConsumer; connectionFactory = new ActiveMQConnectionFactory(username,password,brokeurl); try { connection = connectionFactory.createConnection(); connection.start(); session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); topic = session.createTopic(queuename); messageConsumer = session.createConsumer(topic); //多条消息处理 messageConsumer.setMessageListener(new MessageListener() { public void onMessage(Message message) { BytesMessage bytesMessage = (BytesMessage) message; try { byte[] bytes = new byte[(int) bytesMessage.getBodyLength()]; bytesMessage.readBytes(bytes); FileOutputStream fileOutputStream = new FileOutputStream(new File("E://" + UUID.randomUUID() + ".jpg")); fileOutputStream.write(bytes); }catch (Exception e){ System.out.println("......................"); } } }); } catch (JMSException e) { e.printStackTrace(); } } }
messageListener会注册一个监听器,当有消息到达的时候会回调它的Onmessage()方法。
2.4延迟投递
Property name | type | description |
AMQ_SCHEDULED_DELAY | long | 延迟投递的时间 |
AMQ_SCHEDULED_PERIOD | long | 重复投递的时间间隔 |
AMQ_SCHEDULED_REPEAT | int | 重复投递次数 |
AMQ_SCHEDULED_CRON | String | Cron表达式 |
3.ActiveMQ持久化方式
消息持久性对于可靠消息传递来说应该是一种比较好的方法,有了消息持久化,即使发送者和接受者不是同时在线或者消息中心在发送者发送消息后宕机了,在消息中心重新启动后仍然可以将消息发送出去,如果把这种持久化和ReliableMessaging结合起来应该是很好的保证了消息的可靠传送。
发送者将消息发送出去后,消息中心首先将消息存储到本地数据文件、内存数据库或者远程数据库等,然后试图将消息发送给接收者,发送成功则将消息从存储中删除,失败则继续尝试。消息中心启动以后首先要检查制定的存储位置,如果有未发送成功的消息,则需要把消息发送出去。
ActiveMQ持久化方式:AMQ、KahaDB、JDBC、LevelDB。