清晰架构(Clean Architecture)的一个理念是隔离程序的框架,使框架不会接管你的应用程序,而是由你决定何时何地使用它们。在本程序中,我特意不在开始时使用任何框架,因此我可以更好地控制程序结构。只有在整个程序结构布局完成之后,我才会考虑用某些库替换本程序的某些组件。这样,引入的框架或第三方库的影响就会被正确的依赖关系所隔离。目前,除了logger,数据库,gRPC和Protobuf(这是无法避免的)之外,我只使用了两个第三方库ozzo-validation¹和YAML²,而其他所有库都是Go的标准库。
你可以使用本程序作为构建应用程序的基础。你可能会问,那么本框架岂不是要接管整个应用程序吗?是的。但事实是,无论是你自建框架还是引进第三方框架,你都需要一个基本框架作为构建应用程序的基础。该基础需要具有正确的依赖性和可靠的设计,然后你可以决定是否引入其他库。你当然可以自己建立一个框架,但你最终可能会花费大量的时间和精力来完善它。你也可以使用本程序作为起点,而不是构建自己的项目,从而为你节省时间和精力。
程序容器是项目中最复杂的部分,是将应用程序的不同部分粘合在一起的关键组件。本程序的其他部分是直截了当且易于理解的,但这一部分不是。好消息是,一旦你理解了这一部分,那么整个程序就都在掌控之中。
容器包(“container” package)的组成部分:
容器包由五部分组成:
-
“容器”(“container”)包:它负责创建具体类型并将它们注入其他文件。 顶级包中只有一个文件“container.go”,它定义容器的接口。
-
“servicecontainer”子包:容器接口的实现。 只有一个文件“serviceContainer.go”,这是“容器”包的关键。 以下是代码。 它的起点是“InitApp”,它从文件中读取配置数据并设置日志记录器(logger)。
type ServiceContainer struct { FactoryMap map[string]interface{ } AppConfig *config.AppConfig } func (sc *ServiceContainer) InitApp(filename string) error { var err error config, err := loadConfig(filename) if err != nil { return errors.Wrap(err, "loadConfig") } sc.AppConfig = config err = loadLogger(config.Log) if err != nil { return errors.Wrap(err, "loadLogger") } return nil } // loads the logger func loadLogger(lc config.LogConfig) error { loggerType := lc.Code err := logFactory.GetLogFactoryBuilder(loggerType).Build(&lc) if err != nil { return errors.Wrap(err, "") } return nil } // loads the application configurations func loadConfig(filename string) (*config.AppConfig, error) { ac, err := config.ReadConfig(filename) if err != nil { return nil, errors.Wrap