V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
limpo
V2EX  ›  Go 编程语言

Go-Spring 轻装上阵,重新出发 v1.0.0 !

  •  
  •   limpo ·
    limpo1989 · 188 天前 · 6315 次点击
    这是一个创建于 188 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    多年前曾经梦想着能有一天能在 Go 语言中使用上 Spring 那样强大的框架,幸运的是我找到了go-spring,一款类似 Spring 的库,我很喜欢它,并且在我的项目中深度使用它,它给我带来了非常酷的编程体验。

    然而很不幸的是最近 go-spring 停止更新了(最近的一次提交停留在九个月之前),一些问题无法得到有效的解决,因此我决定创建一个基于 go-spring 的开源库,我为它修复了一系列 bug ,并添加了一些新得特性,并对代码结构进行了简化,将外部生态从核心库中移除,仅保留核心功能,外部生态预计将来将作为独立的仓库存在,我将持续继续将它维护下去,也希望有感兴趣的人可以一起参与进来一起持续开发它。

    仓库地址: https://github.com/go-spring-projects/go-spring

    特性

    • IoC 容器: 实现了基于反射的控制反转(IoC)容器,支持结构体、函数和常量的注入。这意味着你可以使用' autowired '标签来自动注入依赖,而不必手动管理它们。
    • 配置管理: 受 Spring 的 @Value 注释的启发,Go-Spring 允许您从多个源(如环境变量、文件、命令行参数等)获取配置项。这为配置管理带来了前所未有的灵活性。
    • 配置验证器: 通过支持自定义验证器扩展扩展了其健壮的配置管理功能。这使您能够对属性执行有效性检查,确保仅将有效的配置应用于您的应用程序。
    • 结构化日志: 使用标准库 slog 提供内置日志记录器支持,以实现有效和简化的日志记录。这种增强提供了清晰、简洁和结构良好的日志信息,有助于系统调试和性能监视。
    • 动态属性: 提供动态属性刷新功能,让您无需重新启动应用程序即可动态更新应用程序属性。它满足了需要高可用性和实时响应的应用程序的需求。
    • 依赖序事件: 按照 bean 依赖关系的顺序,确保根据对象的生命周期正确通知初始化和销毁事件。这增强了系统在其生命周期运行中的鲁棒性和可靠性。

    动态属性例子

    允许在运行时动态刷新属性,不仅支持基本数据类型,还支持结构、切片和 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的辛勤付出。

    111 条回复    2023-11-04 11:17:41 +08:00
    1  2  
    FightPig
        101
    FightPig  
       188 天前
    @kirito41dd 没事,rust on spring 估计后面也有人搞🐶
    rxswift
        102
    rxswift  
       188 天前
    @abcdexx vagaa?
    franktopplus
        103
    franktopplus  
       188 天前 via Android
    真没有必要,每个语言有各自的范式。java 需要依赖注入,可以理解为特性,也可理解为缺点
    BBCCBB
        104
    BBCCBB  
       188 天前
    spring 是非常轻量的. 但你项目复杂了引入了各种中间件, 框架. 这就不能怪到 spring 身上了.

    不管什么语言, 项目复杂后能轻量就怪了
    Leviathann
        105
    Leviathann  
       188 天前   ❤️ 1
    你知道 bean 为什么叫 bean 吗?
    java 是咖啡的意思,bean 是豆子,也就是咖啡豆,咖啡豆组成咖啡
    而 jar 是罐子也就是咖啡豆的罐子

    这些词完全都是语义化的,被挪用到其他语言显得格外幽默

    好像很多人不知道编程语言首先是一种语言?
    edisonwong
        106
    edisonwong  
       188 天前
    1. op 牛逼,付出努力,实现并开源,存在即合理
    2. 看到楼上的回复崩不住了😂,gava ? 或许未来再来个 gomcat ? 😂
    potatowish
        107
    potatowish  
       188 天前 via iPhone   ❤️ 1
    @Leviathann 雀食,tomcat 是汤姆猫的意思,猫吃咖啡豆,可以生产猫屎咖啡~

    spring 是春天,春天是猫发情的季节,也是咖啡豆播种的季节……
    Rorysky
        108
    Rorysky  
       187 天前
    真的没必要,就让 spring 留在 java 生态吧
    frank42a
        109
    frank42a  
       187 天前
    @iold 非常重了
    sgwk
        110
    sgwk  
       187 天前
    用 go ,主要是为了方便,轻快,去除 spring 那套。
    ikas
        111
    ikas  
       187 天前
    时代变了.连 spring 的思维都没人想着去理解了
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3419 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 184ms · UTC 11:44 · PVG 19:44 · LAX 04:44 · JFK 07:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.