Go-Spring : Another Go Style!
前言
去年年底的时候,我所在的团队由于业务调整,技术栈也随之发生改变,由之前的 PHP +Java 变成了 Golang + Java。初次接触Golang,颇不适应,首先就是它那不同一般的语法,然后是没有一个成熟好用的开发框架。语法问题时间长了代码写的多了也就慢慢适应了,但是没有顺手的开发框架就太影响开发效率和代码质量了,作为一个资深的 Java + Spring 全家桶开发者,我希望能改变这一现状。经过一段时间的使用和探索,我发现完全可以搞出一套像 Spring 全家桶(Spring Framework + Spring Boot +Spring Cloud)那样的解决方案出来!
Spring 全家桶在 Java 世界的地位自然无需多言,它不仅为 Java 开发者证明了基于注解开发、基于 AOP 开发以及面向接口开发能够给程序带来极大的灵活性,更重要的是带来了依赖注入、声明式事务、统一的异常处理、模块自动化加载、更简单的 Maven 管理、更简单的单元测试等优秀的开发实践。
但是 GoLang 和 Java 毕竟不同,我为什么笃信自己肯定能搞出来呢?要回答这个问题,实际上是在回答另一个问题,即 Java 的哪些语言特性支撑了 Spring 全家桶能够实现那些核心能力,而 GoLang 又有哪些相似的语言特性?
追根溯源,Java 的字节码、反射、注解、包扫描等机制支撑了 Spring 全家桶能够实现 AOP 开发、依赖注入、声明式事务、模块自动化加载等核心特性。GoLang 因为没有字节码,所以不能实现 AOP 。但是 GoLang 有 Tags、Reflection、_ Imports、init() 机制,所以尽管实现起来不一定有 Java 优雅,但是也能实现依赖注入、模块自动化加载这些 Spring 全家桶的最核心特性。而且,尽管 GoLang 无法实现 AOP,但是也可以通过 Middleware 实现同样的功能。
经过一番探索和实践,终于 Go-Spring 诞生了!在我的眼中,Go-Spring 和 GoLang 本身一样,一出生就带着叛逆和创新精神,GoLang 以不同于主流编程语言语法的姿态出现,而 Go-Spring 则在质疑中以面向接口和依赖注入等多种绝对 Java 的特性出现在大家眼前。
特性
Go-Spring 是模仿 Java 的 Spring 全家桶实现的一套 GoLang 的应用程序框架,仍然遵循“习惯优于配置”的原则,提供了依赖注入、自动配置、开箱即用、丰富的第三方类库集成等功能,能够让程序员少写很多的样板代码。总结起来,Go-Spring 至少有以下五大特点:
1. 可扩展的启动器框架,帮你优雅的组织代码。下面这张图展示了一个 rtmp 服务器的启动函数,这里只截取了其中的一部分,可以看到启动函数的代码太长了,而且需要精心组织才能保证代码的可读性。
而使用 Go-Spring 的启动器框架则可以把这些启动过程封装到单独的文件中,使得功能更内聚,代码更清晰。下图展示的就是一个封装好的启动文件。
在使用了 Go-Spring 的启动器框架之后,程序的启动过程就变成了非常简单的一行代码了!
2. 面向接口+依赖注入,灵活替换实现方案。Go-Spring为 Redis 服务提供了统一的 API 接口,但是底层实现却有多种方案。用户在使用 Redis 服务编写业务代码时只需要关注 API 接口,而不需要关心底层采用的是哪种方案。
当然用户最终会选择一个 redis 服务的底层实现,而引入这个实现仅仅只需要一行代码即可!
如果你想换成其他的 redis 底层实现,也仅仅是一行代码的事。
3. 自动绑定配置项,简化配置文件使用。在使用了 Go-Spring 的代码中只需要为变量设置好要绑定的配置项的名称,并在配置文件中添加该配置项,Go-Spring 就会自动帮你完成变量和配置项的绑定工作。
Go-Spring 还支持按照运行环境绑定不同的配置文件,比如当检测到线下环境时Go-Spring 使用 application-test.properties 配置文件,而当检测到线上环境时会使用 application-online.properties配置文件。
4.有效地帮助做好项目的依赖管理!Go-Spring 为每一个模块都提供了一个抽象接口,使用者不需要关心接口内部是怎么实现的,这样能非常容易的解决依赖升级的问题。Go-Spring 保证已发布的所有版本的项目依赖都是正确的,而且 Go-Spring 每发布一个版本都会对依赖进行升级,这样使用者只需要关注 Go-Spring 的版本变化,就能享受到其他依赖自动升级的好处!
5. 让复杂的单元测试变得更简单。GoLang 的单元测试尤其对 http 的单元测试简直烂的要命!使用 Go-Spring 启动的项目能够在单元测试的时候使用真实的项目运行环境,而不是使用一个fake 的 http 环境。
组件
Go-Spring 包含了四个核心项目,其中
go-spring 实现了 IoC 容器和依赖注入等核心功能;
go-spring-boot 提供了自动配置及应用程序的启动框架;
go-spring-cloud 立足开源世界打造人人可用的微服务框架;
go-spring-didi 聚焦滴滴内部技术实现具有滴滴特点的微服务框架。
示例
下面我将通过一个最简单的 http 服务为大家展示如何使用 Go-Spring。
1. 新建 main.go 文件,创建启动程序,并且指定配置文件所在目录。
2. 在程序中引入 echo http 服务。
3. 新建 example.go 文件,实现一个示例服务,并且在 InitController() 函数中注册 http 接口的路由。
4. 将一个示例服务的对象注册到 Go-Spring 的 IoC 容器里,这样 Go-Spring 就能自动地加载用户注册的 http 接口的路由。
5. 在 main.go 文件中引入示例服务所在的包,这样 Go-Spring 框架在启动的时候就能加载示例服务所在的模块。
通过上面的 5 个步骤我们就得到了一个简单但完整的 http 服务,使用 go run main.go 命令启动程序,并使用 curl http://localhost:8080/ 进行测试,可以看到请求的返回结果如下:
{"code":900001,"msg":"biz error"}
OK,是不是已经开始感觉到 Go-Spring 的威力了!下面我们再来看一下使用了 Go-Spring 框架的项目的单元测试会怎么写。
首先,我们可以编写一个 TestMain 函数用于启动真实的 http 服务器。
实际上图展示的代码还可以更精简,精简为一行。
然后,我们可以编写一个测试函数发送真实的 http 请求,也不需要 fake 或者 mock。
执行这个单元测试,你就会发现,你得到了一个完全不用 mock 和 fake ,并且功能完整、可以断点调试的测试环境。
总结
除了上面展示的能够创建 http 服务和单元测试之外,Go-Spring 已经支持了 mysql 服务、redis 服务、kafka 服务、ddmq服务、服务注册和服务发现服务以及多种 rpc 服务,并且更多的新组件和新特性正在源源不断的通过滴滴内源加入进来,未来 Go-Spring 会变得越来越完善,越来越好用!
Another Go Style!我个人认为 Go-Spring 代表了一种新的编程模式,甚至是一种新的生产力方式,我希望大家在使用 Go-Spring 的过程中能够解放思想,提高效率,得到更多的快乐和自由,也多留一些时间给朋友和家人!