The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
limpo

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

  •  
  •   limpo ·
    limpo1989 · Nov 3, 2023 · 8380 views
    This topic created in 923 days ago, the information mentioned may be changed or developed.

    前言

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

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

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

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

    spring 是春天,春天是猫发情的季节,也是咖啡豆播种的季节……
    Rorysky
        108
    Rorysky  
       Nov 3, 2023
    真的没必要,就让 spring 留在 java 生态吧
    frank42a
        109
    frank42a  
       Nov 3, 2023
    @iold 非常重了
    sgwk
        110
    sgwk  
       Nov 4, 2023
    用 go ,主要是为了方便,轻快,去除 spring 那套。
    ikas
        111
    ikas  
       Nov 4, 2023
    时代变了.连 spring 的思维都没人想着去理解了
    1  2  
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   6087 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 105ms · UTC 02:43 · PVG 10:43 · LAX 19:43 · JFK 22:43
    ♥ Do have faith in what you're doing.