一.简介
1.什么是消息队列
activeMQ是基于java的JMS应用程序接口实现的消息队列
2.什么时候用消息队列
1) 异步处理场景 : 邮件服务,订阅服务
2) 高并发场景 : 短时间内大量访问,服务器无法及时处理,
可以将一些处理放到队列中,后续处理
3) 应用间解耦 : 生产者端和消费者端可以实现解耦,
不管一端有没有问题,另一端还可以正常工作.
3.ActiveMQ的特性:(前提:由于ActiveMQ是一个网络服务)
1)多语言:支持多种语言:Java,C,C++,C#,Python,PHP
2)跨平台:支持绝大多数JavaEE服务器
3)多项目:可以多个项目同时连接
4.ActiveMQ的代码流程
1)获取JMS ConnectionFactory.通过提供特定环境的链接信息构造工厂
2)通过factory构造JMS Connection并启动
3)通过Connection创建JMS Session
4)指定JMS destination
5)创建JMS producer或者创建JMS Message并提供destination
6)创建JMS consumer或者注册JMS Message listener
7)发送和接收JMS Message
8)关闭所有JMS资源
2.前期准备步骤:
1.下载ActiveMQ到local文件夹,并拷贝到/usr/local/activemq
2.控制台 cd /usr/local/activemq/bin
运行./activemq start
3.在浏览器输入http://127.0.0.1:8161/
点击左边连接第一个链接
密码,用户名都是admin
4.导入依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.0</version>
</dependency>
二.编写步骤
1.建立一个activemq包,创建两个类,Producer和Consumer
-
Producer : 消息生产者
public class Producer {
//全局变量
//1.ActiveMQ默认的用户名,密码,URL
private static String USERNAME =ActiveMQConnection.DEFAULT_USER;
private static String PASSWORD =ActiveMQConnection.DEFAULT_PASSWORD;
private static String BROKER_URL =ActiveMQConnection.DEFAULT_BROKER_URL;
//2.连接工厂
ConnectionFactory connectionFactory = null;
//3.连接对象
Connection connection = null;
//4.会话
Session session = null;
//5.针对线程的容器
//目的:同一个变量复制给多个线程使用,使他们都有自己的局部变量
ThreadLocal<MessageProducer> threadLocal =
new ThreadLocal<MessageProducer>();
//6.线程安全的integer(一个线程操作完,才轮到另一个线程)
AtomicInteger count =new AtomicInteger(0);
//初始化
public void init(){
try {
//1.通过连接信息创建连接工厂
connectionFactory =
new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKER_URL);
//2.通过连接工厂创建一个连接对象
connection = connectionFactory.createConnection();
//3.开启连接
connection.start();
//4.设置回话
//当第一个参数填true,后面一般都使用SESSION_TRANSACTED
//当第一个参数填false,后面有两种选择:
// 1.AUTO_ACKNOWLEDGE:自动签收
// 2.CLIENT_ACKNOWLEDGE:客户端代码签收
session = connection.createSession(true,Session.SESSION_TRANSACTED);
} catch (JMSException e) {
e.printStackTrace();
}
}
//发送方法
public void sendMessage(String queueName){
try {
//1.创建一个队列
Queue queue = session.createQueue(queueName);
//2.消息生产者
MessageProducer messageProducer = null;
//3.判断线程容器是否包含变量
if (threadLocal.get() !=null){
messageProducer = threadLocal.get();
}else {
//如果threadLocal取值为空
//就使用session创建一个消息生产者
messageProducer = session.createProducer(queue);
threadLocal.set(messageProducer);
}
//4.利用死循环不间断的发送消息(必须可控:1.不能太快 2.得有出口)
while (true){
//设置发送频率,每秒发送一个请求
Thread.sleep(1000);
//计数
int num = count.getAndIncrement();
//创建消息
TextMessage msg = session.createTextMessage(Thread.currentThread().getName()+"producer:生产消息!!!,count:"+num);
System.out.println(Thread.currentThread().getName()+"producer:生产消息!!!,count:"+num);
//发送消息
messageProducer.send(msg);
//提交事务
session.commit();
}
} catch (JMSException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
-
Consumer : 消息的消费者
注 : 除了接收请求有一些区别,其他地方和Producer完全一样
public class Consumer {
private static String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static String BROKER_URL = ActiveMQConnection.DEFAULT_BROKER_URL;
ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
ThreadLocal<MessageConsumer> threadLocal =
new ThreadLocal<MessageConsumer>();
AtomicInteger count =new AtomicInteger(0);
public void init(){
try {
connectionFactory =
new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKER_URL);
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
} catch (JMSException e) {
e.printStackTrace();
}
}
//接受消息的方法
public void getMessage(String queueName){
try {
Queue queue = session.createQueue(queueName);
MessageConsumer messageConsumer = null;
if(threadLocal.get()!=null){
messageConsumer = threadLocal.get();
}else {
messageConsumer = session.createConsumer(queue);
threadLocal.set(messageConsumer);
}
//接受请求
while (true){
//每秒处理一个请求,可以和发送端不同
Thread.sleep(1000);
//接受消息
TextMessage msg =
(TextMessage) messageConsumer.receive();
if (msg!=null){
System.out.println("接受到消息:"+msg.getText());
//确认消息,告诉中间件消息处理完毕
msg.acknowledge();
}else {
//如果msg是空值,说明没有消息可以处理,跳出循环
break;
}
}
} catch (JMSException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.编写线程ProducerThread和ConsumerThread
1)实现Runnable接口
2)复写run( )方法
3)添加构造方法和对应的类对象
4)在run中调用发送和接受方法
public class ProducerThread implements Runnable {
private Producer producer;
public ProducerThread(Producer producer) {
this.producer = producer;
}
public void run() {
producer.sendMessage("0602");
}
}
public class ConsumerThread implements Runnable {
private Consumer consumer;
public ConsumerThread(Consumer consumer) {
this.consumer = consumer;
}
public void run() {
consumer.getMessage("0602");
}
}
3.编写测试类
public class ProducerTest {
public static void main(String[] args) {
Producer producer = new Producer();
producer.init();
new Thread(new ProducerThread(producer)).start();
}
}
public class ConsumerTest {
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.init();
new Thread(new ConsumerThread(consumer)).start();
new Thread(new ConsumerThread(consumer)).start();
new Thread(new ConsumerThread(consumer)).start();
}
}