本次解读的源码是go-micro框架中registry仓库的配置,我们通常用以下这段代码来配置etcd 。
newRegistry := etcdv3.NewRegistry(func (options *registry.Options) {
options.Addrs = []string{"192.168.100.151:2379"}
})
service := micro.NewService(
micro.Registry(newRegistry),
)
这段代码内部的实现本质在于,创建Registry对象完成,返回对象之前,给该对象配置相关属性。
解读分析
我根据源码重新写了一段类似的代码,实现的原理是相同的。这段源码使用函数参数的形式来给生成的实例注入属性。
package main
import "fmt"
type Animal struct {
name string
}
type Dog struct {
animal Animal
action string
}
type AniFunc func (*Animal)
func configure(d *Dog, af ...AniFunc) {
/*
不断遍历传入的函数,每个函数中的赋值语句都会作用于传参的对象中,更新对应属性
*/
for _, o := range af {
/*
核心代码:此时o为对应的函数
o := func(animal *Animal) {
animal.name = "animal"
}
那么此时 &d.animal取到了实例化对象的地址,传给了指针对象参数
通过指针对象参数,可以直接操作该实例化参数的属性,也就实现了配置信息的注入
*/
o(&d.animal)
}
fmt.Printf("type:%T, value:%+v", d, d)
}
func NewDog(af ...AniFunc) *Dog {
a := &Dog{
animal: Animal{},
}
configure(a, af...)
return a
}
func main() {
NewDog(func(animal *Animal) {
animal.name = "animal"
}, func(animal *Animal) { // 后面的属性会覆盖前面相同的属性,即name=lion
animal.name = "lion"
})
}
框架源码
type Option func(*Options)
type etcdRegistry struct {
client *clientv3.Client
options registry.Options
sync.RWMutex
register map[string]uint64
leases map[string]clientv3.LeaseID
}
func NewRegistry(opts ...registry.Option) registry.Registry {
e := &etcdRegistry{
options: registry.Options{},
register: make(map[string]uint64),
leases: make(map[string]clientv3.LeaseID),
}
configure(e, opts...)
return e
}
func configure(e *etcdRegistry, opts ...registry.Option) error {
config := clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"},
}
for _, o := range opts {
o(&e.options)
}
if e.options.Timeout == 0 {
e.options.Timeout = 5 * time.Second
}
if e.options.Secure || e.options.TLSConfig != nil {
tlsConfig := e.options.TLSConfig
if tlsConfig == nil {
tlsConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
config.TLS = tlsConfig
}
if e.options.Context != nil {
u, ok := e.options.Context.Value(authKey{}).(*authCreds)
if ok {
config.Username = u.Username
config.Password = u.Password
}
}
var cAddrs []string
for _, address := range e.options.Addrs {
if len(address) == 0 {
continue
}
addr, port, err := net.SplitHostPort(address)
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
port = "2379"
addr = address
cAddrs = append(cAddrs, net.JoinHostPort(addr, port))
} else if err == nil {
cAddrs = append(cAddrs, net.JoinHostPort(addr, port))
}
}
// if we got addrs then we'll update
if len(cAddrs) > 0 {
config.Endpoints = cAddrs
}
cli, err := clientv3.New(config)
if err != nil {
return err
}
e.client = cli
return nil
}
|
请发表评论