多年前曾经梦想着能有一天能在 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 22
Go,Spring,轻装上阵,这三个词同时出现有点难绷……
|
2
iold 2023-11-03 10:33:55 +08:00 1
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 12
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 2023-11-03 11:04:53 +08:00
要是我写的项目用这玩意,我直接给他删库了。
|
25
xingjue 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 1
Javaer 又来嚯嚯其他语言了
|
36
Dogtler 2023-11-03 11:19:40 +08:00 1
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 1
> 多年前曾经梦想着能有一天能在 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
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 1
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 ,让每个人感受寒冬
|
90
limpo OP @beidounanxizi 啥,go sdk 自带 Java 库?真没用过
|
91
dongya 2023-11-03 15:20:08 +08:00
别来卷 go 了,
|
92
jyhmijack 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
别这样,你们给楼主打击到了😂支持社区开花,不管是什么花
|