ActiveMQ介绍
- MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。
- MQ的消费-生产者模型的一个典型的代表,一端往消息队列中不断的写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似
- JMS即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
- Message消息分为几种类型,它们分别携带:简单文本(TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。
- JMS是一个用于提供消息服务的技术规范,它制定了在整个消息服务提供过程中的所有数据结构和交互流程。而MQ则是消息队列服务,是面向消息中间件(MOM)的最终实现,是真正的服务提供者;MQ的实现可以基于JMS,也可以基于其他规范或标准。
支持JMS的开源MQ:目前选择的最多的是ActiveMQ。
ActiveMQ特点
- 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,Stomp REST,WSNotification,XMPP,AMQP
- 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
- 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
- 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
- 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
- 支持通过JDBC和journal提供高速的消息持久化
- 从设计上保证了高性能的集群,客户端-服务器,点对点
- 支持Ajax
- 支持与Axis的整合
- 可以很容易得调用内嵌JMS provider,进行测试
- ActiveMQ速度非常快;一般要比jbossMQ快10倍。
优点
是一个快速的开源消息组件(框架),支持集群,同等网络,自动检测,TCP,SSL,广播,持久化,XA,和J2EE1.4容器无缝结合,并且支持轻量级容器和大多数跨语言客户端上的Java虚拟机。消息异步接受,减少软件多系统集成的耦合度。消息可靠接收,确保消息在中间件可靠保存,多个消息也可以组成原子事务。
缺点
ActiveMQ默认的配置性能偏低,需要优化配置,但是配置文件复杂,ActiveMQ本身不提供管理工具;示例代码少;主页上的文档看上去比较全面,但是缺乏一种有效的组织方式,文档只有片段,用户很难由浅入深进行了解,二、文档整体的专业性太强。在研究阶段可以通过查maillist、看Javadoc、分析源代码来了解。
ActiveMQ应用场景
- 流量肖锋
- 任务异步处理
- 可以解耦合
- 消息通讯
SpringBoot集成ActiveMQ的使用demo(代码包含queue和topic两种使用方式)
- ActiveMQ配置信息application.properties文件
spring:
activemq:
user: admin
password: admin
broker-url: tcp://127.0.0.1:61616
pool: //连接池设置
enabled: true //是否开启连接池
max-connections: 10 //最大连接数
- ActiveMQ配置信息类
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.jms.Queue;
import javax.jms.Topic;
@Component
public class ActiveMQConfig {
@Bean
public Queue queue () {
return new ActiveMQQueue("queueTest"); //创建queue
}
@Bean
public Topic topic () {
return new ActiveMQTopic("topicTest"); //创建topic
}
}
- producer类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import javax.jms.Destination;
import javax.jms.Queue;
import javax.jms.Topic;
@Component
@EnableScheduling //快速开启任务调度
public class ActiveMQProducer {
Logger logger = LoggerFactory.getLogger(ActiveMQProducer.class);
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private Queue queue;
@Autowired
private Topic topic;
public void sendByQueue () {
System.out.println("ActiveMQ以 Queue 准备接受用户消息");
logger.info("【sendByQueue start】ActiveMQ以 Queue 准备接受用户消息");
jmsTemplate.convertAndSend(this.queue , "queue每三秒执行一次");
logger.info("【sendByQueue success】ActiveMQ以 Queue 接受用户消息成功");
}
//@Scheduled(fixedDelay = 5000) //每五秒执行一次该方法
public void sendByQueue (Destination destination , String message) {
System.out.println("ActiveMQ以 Queue 准备接受用户消息");
logger.info("【sendByQueue start,destination is + " + destination + " ,message is " + message + "】ActiveMQ以 Queue 准备接受用户消息");
logger.info("【sendByQueue start】ActiveMQ以 Queue 准备接受用户消息");
this.jmsTemplate.convertAndSend(destination , message);
}
public void sendByTopic (Destination destination , String message) {
System.out.println("ActiveMQ以 Topic 准备接受用户消息");
logger.info("【sendByTopic start,destination is + " + destination + " ,message is " + message + "】ActiveMQ以 Topic 准备接受用户消息");
logger.info("【sendByTopic start】ActiveMQ以 Topic 准备接受用户消息");
this.jmsTemplate.convertAndSend(destination , message);
}
}
- comsumer类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import javax.jms.Queue;
import javax.jms.Topic;
@Component
@EnableScheduling
public class ActiveMQComsumer {
Logger logger = LoggerFactory.getLogger(ActiveMQComsumer.class);
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private Queue queue;
@Autowired
private Topic topic;
@JmsListener(destination = "queueTest")
public void receiveByQueue (String message) {
System.out.println("以Queue收到的消息为:" + message);
logger.info("【receiveByQueue succeed】以 Queue 开始接受来自AvtiveMQ的消息");
}
@JmsListener(destination = "topicTest")
public void receiveByTopic1 (String message) {
System.out.println("receiveByTopic1以Topic收到消息:" + message);
logger.info("【receiveByTopic1 succeed】以 Topic 成功接受来自AvtiveMQ的消息");
}
@JmsListener(destination = "topicTest")
public void receiveByTopic2 (String message) {
System.out.println("receiveByTopic1以Topic收到消息:" + message);
logger.info("【receiveByTopic2 succeed】以 Topic 成功接受来自AvtiveMQ的消息");
}
}
- Controller访问ActiveMQ
import com.ruider.common.Result;
import com.ruider.utils.ActiveMQ.ActiveMQProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Queue;
import javax.jms.Topic;
/**
* ActiveMQ controller消息中间件
*/
@RestController
@RequestMapping("message")
public class ActiveMQController {
private final Logger logger = LoggerFactory.getLogger(ActiveMQController.class);
@Autowired
private Queue queue;
@Autowired
private Topic topic;
@Autowired
private ActiveMQProducer activeMQProducerTest;
@GetMapping("activeMQQueueProduce")
public Result activeMQQueueProduce (String message) {
Result result = new Result();
try {
activeMQProducerTest.sendByQueue(this.queue , message);
result.setIsSuccess(true);
result.setMessage("发送消息成功,MQ收到消息");
logger.info("【activeMQQueueProduce success】发送消息成功,MQ Queue收到消息");
return result;
}
catch(Exception e) {
result.setIsSuccess(false);
result.setCode(Result.EXCEPTION_CODE);
result.setMessage("发送消息失败,MQ Queue未收到消息");
logger.error("【activeMQQueueProduce fail】发送消息失败,MQ Queue未收到消息"+ e);
return result;
}
}
@GetMapping("activeMQTopicProduce")
public Result activeMQTopicProduce (String message) {
Result result = new Result();
try {
activeMQProducerTest.sendByTopic(this.topic , message);
result.setIsSuccess(true);
result.setMessage("发送消息成功,MQ Topic收到消息");
logger.info("【activeMQTopicProduce success】发送消息成功,MQ Topic收到消息");
return result;
}
catch(Exception e) {
result.setIsSuccess(false);
result.setCode(Result.EXCEPTION_CODE);
result.setMessage("发送消息失败,MQ Topic未收到消息");
logger.error("【activeMQTopicProduce fail】发送消息失败,MQ Topic未收到消息"+ e);
return result;
}
}
}
- Controller类中使用到的Result类做前端与后台的交互
/**
* Created by mahede on 2018/11/28.
*/
public class Result {
public static final int ERROR_CODE = 100;
public static final int ALREADY_SAVED = 110;
public static final int FAIL_CODE = 120;
public static final int SUCCESS_CODE = 140;
public static final int EXCEPTION_CODE = 150;
public static final int OVER_NUMBER = 160;
public static final int OVER_TIME = 170;
int code;
String message;
Object data;
boolean isSuccess;
public Result(){ this.code = SUCCESS_CODE;}
public Result(int code, String message, Object data, boolean isSuccess) {
this.code = code;
this.message = message;
this.data = data;
this.isSuccess = isSuccess;
}
public Result(boolean isSuccess, Object data, String message) {
this.message = message;
this.data = data;
this.isSuccess = isSuccess;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", message='" + message + '\'' +
", data=" + data +
", isSuccess=" + isSuccess +
'}';
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public boolean getIsSuccess() {
return isSuccess;
}
public void setIsSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}