在springboot中,如果是使用实体类进行数据的生产及消费则需要保证序列化后的实体类在消费者和生产者中的路径需保持一致,因为其使用的是JDK进行的序列化。
以下是springboot中交换机和队列,及其绑定的相关代码:
@Configuration
public class RabbitConfig {
@Bean
public TopicExchange topicExchange() {
return new TopicExchange(这里是交换机名,自己定义,但需要和消费者保持一致);
}
@Bean
public Queue queue() {
/**
* durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
* exclusive 表示该消息队列是否只在当前connection生效,默认是false
* auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
*/
return new Queue(这里是队列名, true, false, false);
}
// 绑定交换机和队列
@Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(topicExchange()).with(RabbitConstant.ROUTIN_KEY);
}
}
以下是生产者发送消息的代码:
@Component
public class Producer {
@Resource
private RabbitTemplate rabbitTemplate;
RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
@Override
/**
* CorrelationData 消息的附加信息,即自定义id
* isack 代表消息是否被broker(MQ)接收 true 代表接收 false代表拒收。
* cause 如果拒收cause则说明拒收的原因,帮助我们进行后续处理
*/
public void confirm(CorrelationData correlationData, boolean isAck, String cause) {
System.out.println("correlationData-----------" + correlationData);
System.out.println("ack-----------" + isAck);
if (isAck == false) {
System.err.println(cause);
}
}
};
RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int code, String text, String exchange, String routingKey) {
System.err.println("Code:" + code + ",text:" + text);
System.err.println("Exchange:" + exchange + ",routingKey:" + routingKey);
}
};
public void sendMsg(Employee employee) {
//CorrelationData对象的作用是作为消息的附加信息传递,通常我们用它来保存消息的自定义id
CorrelationData data = new CorrelationData(employee.getEmpno() + new Date().getTime());
rabbitTemplate.setConfirmCallback(confirmCallback);
rabbitTemplate.setReturnCallback(returnCallback);
rabbitTemplate.convertAndSend(RabbitConstant.EXCHANGE_EMP, RabbitConstant.ROUTIN_KEY, new Gson().toJson(employee), data);
}
}
以下是消费者从队列中获取消息,并对消息进行处理的方法:
//@RabbitListener注解用于声明式定义消息接受的队列与exhcange绑定的信息
//在SpringBoot中,消费者这端使用注解获取消息
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = RabbitConstant.QUEUE_EMP, durable = "true"),
exchange = @Exchange(value = RabbitConstant.EXCHANGE_EMP, durable = "true", type = "topic"),
key = "hr.#"
)
)
//用于接收消息的方法
@RabbitHandler
//通知SpringBoot下面的方法用于接收消息。
// 这个方法运行后将处于等待的状态,有新的消息进来就会自动触发下面的方法处理消息
//@Payload 代表运行时将消息反序列化后注入到后面的参数中
public void handleMessage(@Payload String employee, Channel channel,
@Headers Map headers) {
System.out.println("------------------");
System.out.println("接收到:" + employee);
Employee emp = new Gson().fromJson(employee, Employee.class);
System.err.println(emp.toString());
Long tag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
try {
channel.basicAck(tag, false);
} catch (IOException e) {
e.printStackTrace();
}
}
rabbitmq使用中还需要进行集群配置,主要是通过Haproxy进行MQ集群的负载均衡,以下是Mirror镜像集群的命令:
#修改hostname
vim /etc/hostname
m1
m2
#修改hosts集群设备
vim /etc/hosts
192.168.132.137 m1
192.168.132.139 m2
#开放防火墙 4369/5672/15672/25672端口
firewall-cmd --zone=public --add-port=4369/tcp --permanent
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --zone=public --add-port=25672/tcp --permanent
#重载防火墙
firewall-cmd --reload
#重启服务器
reboot
#同步.erlang.coolie
find / -name *.cookie
scp /var/lib/rabbitmq/.erlang.cookie 192.168.132.134:/var/lib/rabbitmq/
#两个电脑启动MQ服务
rabbit-server
# 停止应用 通过rabbitmqctl status 可以查看当前rabbitmactl默认操作的节点信息
rabbitmqctl stop_app
# 将当前节点加入到一个集群中 默认磁盘节点被加入的节点只要是集群中的一员,其他节点都能够马上感受到集群节点的变化
rabbitmqctl join_cluster rabbit@m1
# 重新启动当前节点
rabbitmqctl start_app
#查看集群信息
rabbitmqctl cluster_status
以下是haproxy.cfg配置文件的具体内容:
#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
# http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
#对MQ集群进行监听
listen rabbitmq_cluster
bind 0.0.0.0:5672
option tcplog
mode tcp
option clitcpka
timeout connect 1s
timeout client 10s
timeout server 10s
balance roundrobin
server node1 192.168.132.137:5672 check inter 5s rise 2 fall 3
server node2 192.168.132.139:5672 check inter 5s rise 2 fall 3
#开启haproxy监控服务
listen http_front
bind 0.0.0.0:1080
stats refresh 30s
stats uri /haproxy?stats
stats auth admin:admin