多年前曾经梦想着能有一天能在 Go 语言中使用上 Spring 那样强大的框架,幸运的是我找到了go-spring,一款类似 Spring 的库,我很喜欢它,并且在我的项目中深度使用它,它给我带来了非常酷的编程体验。
然而很不幸的是最近 go-spring 停止更新了(最近的一次提交停留在九个月之前),一些问题无法得到有效的解决,因此我决定创建一个基于 go-spring 的开源库,我为它修复了一系列 bug ,并添加了一些新得特性,并对代码结构进行了简化,将外部生态从核心库中移除,仅保留核心功能,外部生态预计将来将作为独立的仓库存在,我将持续继续将它维护下去,也希望有感兴趣的人可以一起参与进来一起持续开发它。
仓库地址: https://github.com/go-spring-projects/go-spring
允许在运行时动态刷新属性,不仅支持基本数据类型,还支持结构、切片和 Map 类型。
package main import ( "fmt" "log/slog" "net/http" "github.com/go-spring-projects/go-spring/dync" "github.com/go-spring-projects/go-spring/gs" ) type Handler struct { Open dync.Bool `value:"${server.open:=true}"` } func (h *Handler) OnInit(ctx gs.Context) error { http.HandleFunc("/server/status", func(writer http.ResponseWriter, request *http.Request) { if !h.Open.Value() { http.Error(writer, "server closed", http.StatusNotAcceptable) return } fmt.Fprint(writer, "server running") }) return nil } type Server struct { Logger *slog.Logger `logger:""` } func (s *Server) OnInit(ctx gs.Context) error { props := ctx.(gs.Container).Properties() http.HandleFunc("/server/status/open", func(writer http.ResponseWriter, request *http.Request) { props.Set("server.open", "true") s.Logger.Info("server opened") }) http.HandleFunc("/server/status/close", func(writer http.ResponseWriter, request *http.Request) { props.Set("server.open", "false") s.Logger.Info("server closed") }) go func() { http.ListenAndServe(":7878", nil) }() return nil } func main() { gs.Object(new(Handler)) gs.Object(new(Server)) if err := gs.Run(); nil != err { panic(err) } } // Output: // // $ curl http://127.0.0.1:7878/server/status // server running // // $ curl http://127.0.0.1:7878/server/status/close // // $ curl http://127.0.0.1:7878/server/status // server closed // // $ curl http://127.0.0.1:7878/server/status/open // // $ curl http://127.0.0.1:7878/server/status // server running
Go-Spring
允许您注册自定义值验证器。如果值验证失败,则Go-Spring
将在启动阶段报告一个错误。
在这例子中, 我们将使用 go-validator/validator, 您可以参考这个示例来注册您的自定义验证器。
package main import ( "fmt" "log/slog" "github.com/go-spring-projects/go-spring/conf" "github.com/go-spring-projects/go-spring/gs" "gopkg.in/validator.v2" ) const validatorTagName = "validate" type validatorWrapper struct { validator *validator.Validator } func (v *validatorWrapper) Field(tag string, i interface{}) error { if 0 == len(tag) { return nil } return v.validator.Valid(i, tag) } func init() { conf.Register(validatorTagName, &validatorWrapper{validator: validator.NewValidator().WithTag(validatorTagName)}) } //-------------------------------------------------------------------------- type DBOptions struct { UserName string `value:"${username}"` Password string `value:"${password}"` IP string `value:"${ip}"` Port int32 `value:"${port}" validate:"min=1024,max=65535"` DB string `value:"${db}" validate:"nonzero"` } type MysqlDatabase struct { Logger *slog.Logger `logger:""` Options DBOptions `value:"${db}"` } func (md *MysqlDatabase) OnInit(ctx gs.Context) error { md.Logger.Info("mysql connection summary", "url", fmt.Sprintf("mysql://%s:%s@%s:%d/%s", md.Options.UserName, md.Options.Password, md.Options.IP, md.Options.Port, md.Options.DB)) return nil } func main() { gs.Property("db.username", "admin") gs.Property("db.password", "123456") gs.Property("db.ip", "127.0.0.1") gs.Property("db.port", "0") // set db.port=0 gs.Property("db.db", "test") gs.Object(new(MysqlDatabase)) if err := gs.Run(); nil != err { panic(err) } } // // Output: // panic: container refresh failed // object bean "main/main.MysqlDatabase:MysqlDatabase" /projects/go-project/gocase/validator/main.go:58 // bind MysqlDatabase.Options error: validate MysqlDatabase.Options.Port error: less than min
更多特性请参考说明: go-spring-projects/go-spring
最后还要感谢原作者lvan100的辛勤付出。
![]() | 1 banmuyutian 2023-11-03 10:32:45 +08:00 ![]() Go,Spring,轻装上阵,这三个词同时出现有点难绷…… |
![]() | 2 iold 2023-11-03 10:33:55 +08:00 ![]() Spring 轻吗 |
3 yazinnnn0 2023-11-03 10:37:12 +08:00 讲道理, 只说 spring 是轻量的, 当初 spring 开发出来就是为了取代重量级框架 EJB |
4 sunny352787 2023-11-03 10:39:59 +08:00 为啥要整这么复杂? gin 的路由不好用吗? go 又没有注解,你是不是还得自己加个依赖注入啥的?可别整这么一大坨了,就简单写几个 func 处理逻辑挺好 |
![]() | 5 biu7 2023-11-03 10:41:20 +08:00 你这项目名看上去就不轻装 |
![]() | 6 limpo OP |
![]() | 8 limpo OP @sunny352787 简单的项目确实不需要它,直接撸就行,当你的项目有一定规模的时候,这个时候维护依赖初始化,以及各种属性初始化,就会变得繁琐,也许为了加一个配置参数,要修改很多相关的多个接口 |
![]() | 9 ixx 2023-11-03 10:47:48 +08:00 这东西应该只对 java 转 go 的友好但也是一种限制 毕竟 原生写 go 的人应该都不习惯 java 这一套 所以用习惯了自己觉得会 go 了 可能一看别人代码还是会懵 毕竟实现思路不一样 |
10 xiaocaiji111 2023-11-03 10:47:54 +08:00 啊这,我还是用 spring 吧,轻量级项目用 gin 甚至不用框架都搞定了。 |
11 abcdexx 2023-11-03 10:48:26 +08:00 ![]() g...g.... gava? |
![]() | 12 tinyzilan123 2023-11-03 10:51:55 +08:00 可以改名成 go-summer 简称还是 gs |
![]() | 13 Oktfolio 2023-11-03 10:53:29 +08:00 Java 警告 |
![]() | 14 limpo OP @ixx 是的,我开始接触到依赖注入这个概念的时候,大呼魔法啊,怎么加个注解对象就有了,后来一顿摸索发现这个东西真的是写业务的神器啊,可以全身贯注到业务上去而不必费心依赖/配置怎么传,或者初始化来 |
15 ZZ74 2023-11-03 10:55:22 +08:00 写 Go 不都是奔着 轻快 去的的么....来个 spring 怎么说呢 应该会有意见吧 |
![]() | 16 limpo OP @xiaocaiji111 是的 Java 里面有很多好东西,比如 netty 的流水线思想,所以我也搞了一个 go-netty ,https://github.com/go-netty/go-netty |
![]() | 19 limpo OP @tinyzilan123 还是你逗 ,取名真的很困难,这不是为了沾 Java 的光 |
![]() | 20 Maboroshii 2023-11-03 11:02:25 +08:00 via Android 是写一个小功能至少要写三个类的嗦写法吗(没写过 java 不太清楚,但是我同事 java 转 go 就是这么嗦。。 |
![]() | 21 lsk569937453 2023-11-03 11:03:25 +08:00 有没有可能 go 不需要依赖注入。。。 |
![]() | 22 TypeErrorNone 2023-11-03 11:03:34 +08:00 哈哈哈哈哈,为啥不继续写 Java ? |
![]() | 23 Smilencer 2023-11-03 11:04:28 +08:00 这。。。啊。。。大道至简。。。 |
![]() | 24 danbai PRO 要是我写的项目用这玩意,我直接给他删库了。 |
![]() | 25 nxcdJaNnmyF9O90X 2023-11-03 11:05:49 +08:00 gava 警告? |
![]() | 26 limpo OP @Maboroshii 是的你说的没错,简单的东西确实没有必要,过度抽象也是没有必要的,还是要合理运用 |
![]() | 27 limpo OP @lsk569937453 萝卜白菜各有所需嘛 |
![]() | 28 limpo OP @TypeErrorNone 我真不是 Java 转过来的,纯就是馋 Java 的生态,但是又不想入 Java 的坑 |
32 tietou 2023-11-03 11:14:03 +08:00 看名字 就感觉不是很轻装 |
![]() | 33 asdfa 2023-11-03 11:16:22 +08:00 |
![]() | 35 me1onsoda 2023-11-03 11:17:32 +08:00 ![]() Javaer 又来嚯嚯其他语言了 |
![]() | 36 Dogtler 2023-11-03 11:19:40 +08:00 ![]() Javaer 又来嚯嚯其他语言了 照搬 Java 那套 明显违背了 Go 哲学 Kiss 原则 |
![]() | 37 mightybruce 2023-11-03 11:24:28 +08:00 关键是 go 实现依赖注入很简单, 不少人或公司可以自己实现了,你除非有什么特别之处很难流行。 社区中类似 spring 的 是 uber 的 fx 。 这个更好,直接让 aop 和 gin 集成 https://github.com/shenyisyn/goft-gin |
![]() | 38 limpo OP |
![]() | 40 limpo OP @mightybruce 是的,uber fx ,google wire ,等众多依赖注入方案都有自己的特点,这也是提供更多的选择给 Gopher 们,毕竟萝卜白菜各有所爱 |
![]() | 41 winglight2016 2023-11-03 11:28:45 +08:00 现在的 spring 已经超过当初的 EJB 多少倍了,哪里还有轻这个概念,IoC 也不是什么好事儿,严重降低代码的可阅读性。 函数式编程已经抛弃了 OOP 的封装,lz 又当成个宝捡回来。。。 |
![]() | 42 mightybruce 2023-11-03 11:30:43 +08:00 我目前简单用用就用的是这个, 我自己还改过一些代码 https://github.com/shenyisyn/goft-ioc |
![]() | 43 yangzzz 2023-11-03 11:31:35 +08:00 一个疑问?既然要这么做为啥不用 java 去开发呢 |
![]() | 44 mightybruce 2023-11-03 11:36:05 +08:00 我老大说过,写业务代码用这个其实就是用来方便控制人的。spring 让写代码的变得没有技术含量, 只关心业务。这个在 go 主力的中间件和云原生领域不好使。 |
![]() | 45 limpo OP @winglight2016 我同意你说的降低代码可读性,鱼和熊掌确实很难同时得到,至于函数式/OOP 之争也不是这几年才有的,虽然但是就个人开发体验来说还是挺好用的,至于路线之争也不会马上就出结果不是吗 |
![]() | 46 limpo OP @mightybruce 我先赞一个,后来学习一下~ |
![]() | 47 FreeEx 2023-11-03 11:40:45 +08:00 @lsk569937453 google:??? https://github.com/google/wire |
![]() | 48 lbp0200 2023-11-03 11:41:08 +08:00 万物皆可 spring ,等 PHP-spring ,Python-spring ,…… |
49 dilu 2023-11-03 11:42:41 +08:00 哥,求求你们这群 java 别来卷 Go 啊,因为我真的是做 Go 的啊 wuwuwu 我就想到点下班怎么就这么难啊 doge |
![]() | 50 limpo OP @mightybruce 也许大部分的程序员工作内容也没有太多技术含量,这部分始终还是需要人去做不是吗,那我的工作就有意义了,go-spring 确实不是为中间件,基础库准备的,它是纯粹的业务框架,用来给堆业务代码的人提供方便。 |
![]() | 54 sadfQED2 2023-11-03 11:54:40 +08:00 via Android 我写过 2 年多 java ,现在写了 3 年多 go 。go 语言本身不支持注解那一套东西,go 的设计理念也不推崇 spring 那一套。 强行实现 java 那一套,我觉得纯粹是影响性能,恶心后续接手的人。 |
55 securityCoding 2023-11-03 11:56:50 +08:00 java 写了 5 年,go2 年 体验下来就是我再也不想写 spring 那套东西 , 代码这东西啊简单直观永远是最优解 |
![]() | 56 mcfog 2023-11-03 11:56:53 +08:00 via Android google wire 和 uber dig 按 XP 选一个就行 |
![]() | 57 yangxiaopeipei 2023-11-03 12:00:01 +08:00 @lbp0200 php 用 laravel |
![]() | 59 limpo OP @securityCoding 但是不得不承认确实也带来很多方便,不然你看现在很多 javaer 离开 spring 都不知道怎么写程序了 |
![]() | 61 sadfQED2 2023-11-03 12:13:21 +08:00 via Android @limpo 大项目中,初始化性能也跟重要,假设你十多个集群,每个集群几百台机器,启动慢的话部署一次要老命 |
62 Leprax 2023-11-03 12:32:28 +08:00 ![]() > 多年前曾经梦想着能有一天能在 Go 语言中使用上 Spring 那样强大的框架 你的梦想很恐怖 |
65 nigerunndayo 2023-11-03 12:57:23 +08:00 @limpo 是这样的 |
66 kirito41dd 2023-11-03 13:31:23 +08:00 还好我 go 转 rust 了,领先一个版本,不然被卷进去了(玩笑 |
![]() | 67 Rehtt 2023-11-03 13:44:14 +08:00 反射式注入。反射一时爽,性能火葬场 |
![]() | 69 limpo OP @kirito41dd 从入门到放弃 3 次了,每次都是在异步一块就看不下去了 |
70 kirito41dd 2023-11-03 13:57:07 +08:00 @limpo 你找一些 futrure 展开的样子看看就明白了,runtime 本质就是个事件驱动模型,tokio 下面是 mio ,和 c libuv libevent 啥的如出一辙,直接入就完了 |
![]() | 71 Miy4mori 2023-11-03 14:04:36 +08:00 不要再嚯嚯我们 Java 码农了,我们真不会试图把 Spring 带去别的社区 |
![]() | 72 qingshui33 2023-11-03 14:05:03 +08:00 @abcdexx 我要笑死了这个 |
![]() | 73 limpo OP @kirito41dd 多谢哈,隔一段时间我还会重新去捡一遍,期待我的第四轮 |
![]() | 75 strong>beidounanxizi 2023-11-03 14:17:15 +08:00 @limpo netty 是因为原生 IO 库写的垃圾 |
![]() | 76 yrzs 2023-11-03 14:25:23 +08:00 怎么名字听上去不怎么轻量,哈哈 |
![]() | 77 SoyaDokio 2023-11-03 14:26:47 +08:00 老实交代,README 是不是英文写了然后机翻中文的(笑 |
![]() | 78 snowlyg 2023-11-03 14:29:08 +08:00 都用 go 了还搞什么 spring? |
![]() | 79 limpo OP @beidounanxizi 语言一般只提供底层接口,上层还是要自己做的,netty 不仅仅解决了原生接口的 bug ,也提供了应用层封装,这才使得网络开发变得容易 |
![]() | 82 limpo OP @snowlyg 主要是依赖注入这块,不仅仅是 spring 独有的,go 里面也有 uber fx, google wire 都是依赖注入思想的实现 |
![]() | 83 Vegetable 2023-11-03 14:35:02 +08:00 去看了一下代码,看到在 go 文件中 NewBean()真的是蚌埠住了,写 java 不好吗 |
![]() | 84 beidounanxizi 2023-11-03 14:41:33 +08:00 ![]() java 恨不得把什么预言都写成一股浓浓の java 味道 |
![]() | 86 beidounanxizi 2023-11-03 14:42:23 +08:00 @limpo 那你用过 go sdk 自带 java 库 还不够好用吗? |
![]() | 87 limpo OP @beidounanxizi 我也不喜欢过度抽象,太琐碎了,go-spring 只是解决了依赖注入,不是一定要按照 Java 那种层层封装的风格去写代码 |
89 Cheivin 2023-11-03 14:46:21 +08:00 @tinyzilan123 我觉得还可以 go-winter ,让每个人感受寒冬 |
![]() | OP @beidounanxizi 啥,go sdk 自带 Java 库?真没用过 |
91 dongya 2023-11-03 15:20:08 +08:00 别来卷 go 了, |
![]() | 92 KKKKale 2023-11-03 15:41:57 +08:00 我们有套用 java spring 写的业务,还在招人用 go 重写一遍呢……https://v2ex.com/t/987054 |
93 brookegas 2023-11-03 15:43:01 +08:00 别背着臭不可闻的 Java 屎山来污染 Go 了 真的,有空好好研究一下 Go Spring 码农自以为得意的所谓“框架”,在 Go 面前就像个 200 斤涂着腮红的肥佬 要不然,你们去祸害 php ,整出一个 Php-Spring ? |
![]() | 94 fgwmlhdkkkw 2023-11-03 16:41:42 +08:00 golang 没有装饰器,全写在 tag 里好变态呀…… |
![]() | 95 zagfai 2023-11-03 16:47:45 +08:00 disgusting |
96 Masoud2023 2023-11-03 16:51:38 +08:00 我真害怕你明天把 tomcat 拿 go 实现一遍。 语言跟语言是不一样的,Go 是自带单例的,喜欢依赖注入方便测试就多做点 interface ,封装点 struct 然后统一注入进去。 拿框架去实现这种东西是要有性能成本的,反射都是要花 CPU 的,换语言不是把原来的思想原封不动换个语言写,你要适应新的编程思想。 |
![]() | 97 wu67 2023-11-03 16:52:10 +08:00 快进到 js-spring. 噢, 原来有 nest.js 啦, 那没事了 /dog |
98 whyso 2023-11-03 17:00:22 +08:00 等一个 rust-spring |
![]() | 99 lifespy 2023-11-03 17:11:05 +08:00 别这样,你们给楼主打击到了支持社区开花,不管是什么花 |