介绍RabbitMq与Erlang
一、简单介绍
1.1 、定义:
Erlang是一种通用的面向并发的编程语言,它有瑞典电信设备制造商爱立信所辖的CS-Lab开发,
目的是创造一种 可以应对大规模并发活动的编程语言和运行环境。
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。消息队列、
一种先进先出的数据结构、存储消息的容器、分布式中的中间件
1.2 、作用(优缺点):
优点:
耦合 :比如A、B、C、D系统都需要抓取馨家梦商城的订单数据 、那么每个系统都会调用接口来获取数据,性能不好,如果把数据发布到队列中,他们每个系统自己到系统中获取就行了
异步 :当保存一条数据A、B、C、D数据库,需要的时间太长,用户体验不好,那么此时需要保存到队列中,节约响应时间
削峰:在高并发的情况下可以减轻数据库的压力
缺点:
系统可用性降低:需要考虑消息丢失或者挂掉等问题
系统复杂性提高:系统加上一个MQ比较复杂,保证消息有没有被消费者消费,处理消息丢失的情况、
保证消息传递的顺序性 等等问题!
1.2 、使用场景:
发送短信与邮件存入消息队列,解决并发情况
保存数据同时需要保存A、B、C、D数据库 时间太长
订单数据存入与该队列中(各个系统之间调用馨家梦商城订单)
二、下载Erlang与RabbitMq
Erlang官网下载地址:http://www.erlang.org/
输入地址点击右上角 download Erlang/OPt
RabbitMq官网地址:https://www.rabbitmq.com/download.html
二、安装Erlang
运行otp_win64_20.2.exe,安装erlang。
三、安装RabbitMq
运行rabbitmq-server-3.5.3.exe,安装rabbitmq。
注意:安装目录的文件夹名称中不要带有空格。
四、配置系统环境变量。
注意:这个安装好Erlang可能会默认存在些,但是下面一张图需要自己配置
然后 windows+R 输入cmd 再输入erl 查看是否安装成功
五、启动并且管理rabbitmq_management
rabbitmq_management是管理后台的ul插件,启动后登录 用户名 密码都是默认 :guest guest
在rabbitmq的安装目录下找到sbin目录。输入cmd,点击回车键。
进入cmd页面,输入rabbitmq-plugins.bat enable rabbitmq_management,回车键
六、开启浏览器访问http://localhost:15672
输入用户名:guest 和 密码 :guest
如果访问失败的话重新启动rabbit-server服务
下次启动电脑的时候随着服务启动而启动
七、大家最喜欢的代码
7.1 、导包 pom.xml
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
7.2 、applicationContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-2.0.xsd">
//下面只是rabbitMq的配置
<!--配置connection-factory,指定连接rabbit server参数 -->
<rabbit:connection-factory id="connectionFactory"
username="wtyMq" password="2016wang" host="localhost" port="5672" />
<!--定义rabbit template用于数据的接收和发送 -->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
exchange="exchangeTest" />
<!--通过指定下面的admin信息,当前producer中的exchange和queue会在rabbitmq服务器上自动生成 -->
<rabbit:admin connection-factory="connectionFactory" />
<!--定义queue -->
<rabbit:queue name="queueTest" durable="true" auto-delete="false" exclusive="false" />
<!-- 定义direct exchange,绑定queueTest -->
<rabbit:direct-exchange name="exchangeTest" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="queueTest" key="queueTestKey"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- 消息接收者 主要用于发送短信 可以监听到队列中是否有消息,如果有,自动调用此类下的方法-->
<bean id="messageReceiver" class="net.shopnc.b2b2c.service.test.MessageConsumer"></bean>
<!-- queue litener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象-->
<rabbit:listener-container connection-factory="connectionFactory">
<rabbit:listener queues="queueTest" ref="messageReceiver"/>
</rabbit:listener-container>
7.2 、java代码
7.2 .1、java生产代码
package net.shopnc.b2b2c.service.test;
import com.rabbitmq.client.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 功能概要:消息产生,提交到队列中去
*
* @author linbingwen
* @since 2016年1月15日
*/
@Service
public class MessageProducer {
@Resource
private AmqpTemplate amqpTemplate;
//调用此方法推送到消息队列中可以自动监听 发送短信 和邮件 可以调此方法
public void sendMessage(Object message){
amqpTemplate.convertAndSend("queueTestKey",message);
}
//此方法可以推送到消息队列中不会监听,必须自己亲自去拿才会被消费
public void testProducer() throws IOException , TimeoutException {
//队列名称 存的时候是什么 ,那么取的时候也要相同
String QUEUE_NAME = "wty";
ConnectionFactory factory = new ConnectionFactory();
// 设置RabbitMQ地址
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
// 创建一个新的连接
Connection connection = factory.newConnection();
// 创建一个频道
Channel channel = connection.createChannel();
// 声明一个队列 -- 在RabbitMQ中,队列声明是幂等性的(一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同),也就是说,如果不存在,就创建,如果存在,不会对已经存在的队列产生任何影响。
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World! 汪太勇测试";
// 发送消息到队列中
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
System.out.println("P [x] Sent '" + message + "'");
// 关闭频道和连接
channel.close();
connection.close();
}
//去消息队列中拿消息 消费方法
public void testConsumer() throws IOException, TimeoutException {
String QUEUE_NAME = "wty";
ConnectionFactory factory = new ConnectionFactory();
// 设置RabbitMQ地址
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
// 创建一个新的连接
Connection connection = factory.newConnection();
// 创建一个频道
Channel channel = connection.createChannel();
// 声明要关注的队列 -- 在RabbitMQ中,队列声明是幂等性的(一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同),也就是说,如果不存在,就创建,如果存在,不会对已经存在的队列产生任何影响。
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println("C [*] Waiting for messages. To exit press CTRL+C");
// DefaultConsumer类实现了Consumer接口,通过传入一个频道,告诉服务器我们需要那个频道的消息,如果频道中有消息,就会执行回调函数handleDelivery
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("C [x] Received '" + message + "'");
}
};
// 自动回复队列应答
channel.basicConsume(QUEUE_NAME, true, consumer);
System.in.read();
}
}
7.2.2 、java消费代码
package net.shopnc.b2b2c.service.test;
import org.apache.commons.lang.SerializationUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import java.util.HashMap;
import java.util.Map;
/**
* 功能概要:消费接收
*
* @author linbingwen
* @since 2016年1月15日
*/
public class MessageConsumer implements MessageListener {
@Override
public void onMessage(Message message) {
try {
String s = new String(message.getBody(), "UTF-8");
System.out.println(s);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
/*
byte[] body = message.getBody();
Object deserialize1 = null;
try {
deserialize1 = SerializationUtils.deserialize(body);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(deserialize1);
*/
//接下来处理自己的业务逻辑代码
//调用发送短信的方法
}
}
7.2.3 、java测试代码
@Controller
public class TestAction extends AdminBaseAction {
@Autowired
private MessageProducer messageProducer;
/**
* 测试生产方法
*/
@RequestMapping(value = "/test/producer", method = RequestMethod.POST)
@ResponseBody
public AdminResultEntity testProducer() {
for(int i = 0; i < 10 ; i++){
try {
Thread.sleep(5000);
messageProducer.sendMessage(i+"发送短信了");
System.out.println(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("==================");
try {
messageProducer.testProducer();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return getSuccessEntity();
}
/**
* 测试消费方法的
*/
@RequestMapping(value = "/test/consumer", method = RequestMethod.POST)
@ResponseBody
public AdminResultEntity testConsumer() {
try {
messageProducer.testConsumer();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return getSuccessEntity();
}