学习rabbitmq在Go中使用时的一些想法:
在学习过程中对代码组织的一些想法
相关环境:
docker:
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management
项目目录如下
--mq
d--consumers
f--consumer.go
f--exchange.go
f--name.go
f--publish.go
f--queue.go
f--rabbitmq.go
f--rabbitmq_test.go
首先明确:
全局只能有一个Conn和Channel
针对不同功能:
file: consumer.go
consumer.go文件中主要是消费者的定义:
type Consume struct {
Queue string
Consume string
AutoAck bool
Exclusive bool
NoLocal bool
NoWait bool
Arg amqp.Table
}
func Consumer(c Consume) (msg <-chan amqp.Delivery, err error) {
return RabbitMqCh.Consume(
c.Queue,
c.Consume,
c.AutoAck,
c.Exclusive,
c.NoLocal,
c.NoWait,
c.Arg,
)
}
在获取消费者对象后,可以在consumers文件中创建相关文件实现对应的业务
file: publish.go
publish文件中主要是生产者相关的定义
type Publish struct {
Exchange string
QueueName string
Mandatory bool
Immediate bool
ContentType string
Body []byte
}
func Publisher(p Publish) error {
fmt.Println(p)
return RabbitMqCh.Publish(
p.Exchange,
p.QueueName,
p.Mandatory,
p.Immediate,
amqp.Publishing{
ContentType: p.ContentType,
Body: p.Body,
},
)
}
考虑到可能有在项目中多个地方进行推送,所以可以定义实现一个项目的默认Publish结构,
在做好合适的规范后,只用关注Body即可(适用于单条队列)
如果是多条队列,需要发送到不同的交换机和队列,可以在此声明一个独立的结构体,传入必要的参数,以替换默认值
file exchange.go
exchange主要定义的是交换机相关:
const (
Fanout = exchangeType("fanout")
Direct = exchangeType("direct")
Topic = exchangeType("topic")
Headers = exchangeType("headers")
)
type exchangeType string
type ExchangeDeclare struct {
Name string
ExchangeType exchangeType
Durable bool
AutoDelete bool
Internal bool
NoWait bool
Arg amqp.Table
}
func RegisterisExchangeDeclare(exs []ExchangeDeclare) {
for _, ex := range exs {
RabbitMqCh.ExchangeDeclare(
ex.Name,
string(ex.ExchangeType),
ex.Durable,
ex.AutoDelete,
ex.Internal,
ex.NoWait,
ex.Arg,
)
}
}
func exchangeInit() {
var exchanges []ExchangeDeclare
exchanges = append(exchanges, ExchangeDeclare{
Name: TestExchange,
ExchangeType: Direct,
Durable: false,
AutoDelete: false,
Internal: false,
NoWait: false,
Arg: nil,
})
RegisterisExchangeDeclare(exchanges)
}
通过数组对象的形式,进行批量注册
file queue.go
queue文件主要定义队列相关:
type QueueDeclare struct {
Name string
Durable bool
DelWnUnused bool
Exclusive bool
NoWait bool
Arg amqp.Table
ExchangeName string
RouteKey string
}
func RegisterisQueueDeclare(Qs []QueueDeclare) {
for _, q := range Qs {
_, err := RabbitMqCh.QueueDeclare(
q.Name,
q.Durable,
q.DelWnUnused,
q.Exclusive,
q.NoWait,
q.Arg,
)
if err != nil {
fmt.Println("queue err ", err)
}
fmt.Println("bingbing")
err = RabbitMqCh.QueueBind(q.Name, q.RouteKey, q.ExchangeName, false, nil)
if err != nil {
fmt.Println("QueueBind err ", err)
}
}
}
func queueInit() {
var qs []QueueDeclare
qs = append(qs, QueueDeclare{
Name: TestQueue,
Durable: false,
DelWnUnused: false,
Exclusive: false,
NoWait: false,
Arg: nil,
ExchangeName: TestExchange,
RouteKey: TestRouteKey,
})
RegisterisQueueDeclare(qs)
}
和exchange相同,通过数组方式统一注册
file name.go
name文件主要是交换机,队列,路由键的常量定义
const (
TestExchange = "test.exchange"
TestQueue = "test.queue"
TestRouteKey = "test.route.key"
)
file rabbitmq.go
rabbitmq文件主要是连接的初始化,以及交换机和队列的初始化
var RabiitMqConn *amqp.Connection
var RabbitMqCh *amqp.Channel
func Conn() {
User := "guest"
Pwd := "guest"
Host := "localhost"
Port := "5672"
url := "amqp://" + User + ":" + Pwd + "@" + Host + ":" + Port + "/"
conn, err := amqp.Dial(url)
if err != nil {
panic(fmt.Sprintf("get mq conn err %v \n", err))
}
RabiitMqConn = conn
ch, err := conn.Channel()
if err != nil {
panic(fmt.Sprintf("get mq ch err %v \n", err))
}
RabbitMqCh = ch
}
func Init() {
Conn()
exchangeInit()
queueInit()
}
在项目开始运行时调用Init()函数进行mq的初始化
当我们需要定义多个交换机和队列时,只需要在exchange和queue注册的地方append对应的结构体,在项目下一次运行时即可加载
同时,在对路由和交换机的名称进行设计后,可以快速的找到对应的交换机和路由,以及相关消费者和生产者的实现
维护方便
以上就是昨天学习的一些想法,欢迎大家评论批评指正,蟹蟹~