在上一篇文章fabric源码阅读4:fabric启动I我们从操作者的角度分析了fabric的启动过程,这篇文章我们就尽量从开发者的角度来看fabric是怎么启动的。

查找peer文件

我们已经知道,启动有两条指令ordererpeer node start,为了方便分析,先看peer的启动。 毫无疑问,peer一定是go编译出来的,问题是我咋知道哪个文件编译出来的啊!

1
2
读Makefile是不可能的,这辈子都不可能读Makefile的,用grep又不会,就是直接瞎找才能找到这样子,瞎找就像回家的感觉一样。
                                                                --窃 格瓦拉

不瞎开玩笑了,读Makefle文件确实是比较好的一个分析方法,但是相对来说确实比较复杂,而且源文件四百多行,真的挺累。使用查找命令,找对应的main函数是一个比较巧妙地办法

1
grep -r "func main"

但是输出的结果太多了,有好多是测试文档的,再去找我也嫌麻烦。那就只好猜了。 看到,整个目录结果中有个peer文件夹,点开一看就有个main.go文件!就是这么巧! * 实际上是人家开发者做的很规范啦

阅读文件

点进来瞅一瞅! 好吧,第一个viper就不认识。。。。。 viper是一个给go用的处理配置文件的工具,支持很多种格式。 首先是对于整个环境变量进行配置。

1
2
3
4
viper.SetEnvPrefix(cmdRoot)
	viper.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	viper.SetEnvKeyReplacer(replacer)

给以后对环境变量的读取设置core的前缀,然后把环境变量的内容读入进来,然后实现._的转换。 然后又看不懂了cobra.Command。。。。。 cobra能创建cli(command line interface),这么说来跟go自带的flag包挺像的,不过肯定是有自己的一套处理机制。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var mainCmd = &cobra.Command{
	Use: "peer",
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		// check for CORE_LOGGING_LEVEL environment variable, which should override
		// all other log settings
		loggingSpec := viper.GetString("logging_level")

		if loggingSpec == "" {
			// if CORE_LOGGING_LEVEL not set, use the value for 'peer' from core.yaml
			loggingSpec = viper.GetString("logging.peer")
		}
		flogging.InitFromSpec(loggingSpec)

		return nil
	},
	Run: func(cmd *cobra.Command, args []string) {
		if versionFlag {
			fmt.Print(version.GetInfo())
		} else {
			cmd.HelpFunc()(cmd, args)
		}
	},
}

第一个Use指明了就是使用peer进行命令行操作。 下面的PersistentPreRunE是对程序运行错误进行处理的,可以不用关注。 然后Run是运行这个指令时候的处理,这个地方就是显示版本或者显示帮助信息。

1
mainFlags := mainCmd.PersistentFlags()

是把peer当成全局的指令,传入的参数都是公用的。然后针对mainFlags设定了一些自己的参数,包括版本日志等内容。 接下来是初始化配置

1
err := common.InitConfig(cmdRoot)

这个函数具体是什么功能呢?就是使用viper读取配置文件。如果配置过FABRIC_CFG_PATH就是用配置的路径,如果没有就使用这几个路径 * /etc/hyperledger/fabric * $GOPATH/src/github.com/hyperledger/fabric/sampleconfig * 当前运行的路径

然后读取这些配置信息。 不错,我们确实在go下面看到了sampleconfig文件夹。具体的内容就不分析了,反正是运行所必须的一些配置。

1
2
3
4
5
	mainCmd.AddCommand(version.Cmd())
	mainCmd.AddCommand(node.Cmd())
	mainCmd.AddCommand(chaincode.Cmd(nil))
	mainCmd.AddCommand(clilogging.Cmd(nil))
	mainCmd.AddCommand(channel.Cmd(nil))

为执行添加对应的操作。比如我们一直念念不忘的peer node start。 跟本程序在同一层的有好多文件夹,包括chaincode,channel,node等,就是对应的这几个命令。 接下来是对MSP的一些配置

1
2
3
var mspMgrConfigDir = config.GetPath("peer.mspConfigPath")
	var mspID = viper.GetString("peer.localMspId")
	err = common.InitCrypto(mspMgrConfigDir, mspID)

这一块我目前也比较乱,整体上就是进行了一些初始化配置。 最后是这么一句

1
2
3
	if mainCmd.Execute() != nil {
		os.Exit(1)
	}

就是把这些都启动起来了,等待命令行的操作。如果出错了,就退出。 这样的话整体就执行了。

总结

目前。对于peer的启动就看完了,但是里面“注册”的子命令(像node start)这种的,还没有来得及看,继续看,继续写。 peer的启动过程是这样 1. 生成viper以及rootCmd 2. 读取对应的配置文件,把配置的信息加载到viper里面 3. 把cmd指令注册到mainCmd上,方便处理命令行 4. 执行execute操作,解析命令行的内容,执行对应的操作。