Go源码解读-registry配置

前言

本次解读的源码是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
}


posted @ 2021-02-18 16:18  ZimskyZeng  阅读(274)  评论(0编辑  收藏  举报