go 框架
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-30 11:04:24 +08:00
app [fix] 启动前订阅停机信号避免就绪瞬间异常退出 2026-10-13 18:11:13 +08:00
bootstrap [refactor] 收敛 bootstrap 并修复释放死锁,web.New 与 CLI 拆分 2026-10-01 03:13:12 +08:00
common [fix] common.debug 全局变量原子化 2026-10-01 12:35:20 +08:00
conf [refactor] 配置段注册入口统一命名为 RegisterSection 2026-10-13 17:53:51 +08:00
database [feat] MySQL 与 Redis 支持 TLS 链路加密,Redis 支持 ACL 用户名 2026-10-01 12:45:45 +08:00
doc [fix] 启动前订阅停机信号避免就绪瞬间异常退出 2026-10-13 18:11:13 +08:00
example [fix] 服务模板拒绝尾随 JSON 内容并补齐鉴权验收 2026-10-13 18:10:21 +08:00
logx [style] 统一历史文件 gofmt 格式 2026-10-01 10:52:59 +08:00
redis [feat] MySQL 与 Redis 支持 TLS 链路加密,Redis 支持 ACL 用户名 2026-10-01 12:45:45 +08:00
web [fix] 启动前订阅停机信号避免就绪瞬间异常退出 2026-10-13 18:11:13 +08:00
.gitignore [feat] 实现显式 TOML 配置与无损双向转换 2026-10-13 17:07:02 +08:00
cli.go [feat] 实现显式 TOML 配置与无损双向转换 2026-10-13 17:07:02 +08:00
cli_test.go [feat] 新增 app 装配层与预制 WebApp,示例改为 WebApp 写法 2026-10-01 03:30:37 +08:00
config_cli_test.go [refactor] 配置段注册入口统一命名为 RegisterSection 2026-10-13 17:53:51 +08:00
config_format_test.go [refactor] 配置段注册入口统一命名为 RegisterSection 2026-10-13 17:53:51 +08:00
config_permissions_linux_test.go [feat] 实现显式 TOML 配置与无损双向转换 2026-10-13 17:07:02 +08:00
go.mod [feat] 实现显式 TOML 配置与无损双向转换 2026-10-13 17:07:02 +08:00
go.sum [feat] 增加配置、日志与注册制初始化框架 2026-09-23 14:26:57 +08:00
middleware.go [refactor] 统一中间件与模块注册接口全称命名 2026-10-13 16:09:44 +08:00
README.md [fix] 启动前订阅停机信号避免就绪瞬间异常退出 2026-10-13 18:11:13 +08:00
tenon.go [feat] 实现显式 TOML 配置与无损双向转换 2026-10-13 17:07:02 +08:00
tenon_test.go [refactor] 统一中间件与模块注册接口全称命名 2026-10-13 16:09:44 +08:00
webapp.go [feat] 实现显式 TOML 配置与无损双向转换 2026-10-13 17:07:02 +08:00
webapp_test.go [feat] 增加 requestid 模块与请求绑定工具,示例与文档全量同步 2026-10-01 10:53:14 +08:00

tenon

通用 Go 服务框架:注册制设计,装配层编排生命周期,当前支持 Web 服务。

简介

tenon 是一个通用服务框架库,将 Web 服务、数据库、缓存、日志等基础设施以注册制方式封装, 使用方只需关注业务分层(router - controller - handler - model - dao),通过 tenon.xxx 快捷调用即可搭起服务骨架。

预制装配层支持注册配置:tenon.NewConfiguredWebApp 注册模块,通过显式命令生成骨架,启动只读加载;tenon.NewWebApp 保留无配置文件的程序化装配。HTTP 由 WebApp 注册为必启模块, 可选模块(日志 / 数据库 / Redis / 请求 ID)按 Enable 清单选择性加载,初始化失败自动回滚,停机自动逆序释放。

项目信息

项目 内容
项目类型 库(Go 框架)
项目定位 通用 Go 服务框架,当前支持 Web 服务
主要语言 / 版本 Go 1.26
构建 / 包管理工具 go build / go mod
测试框架 go test
测试目录约定 测试与源码同目录(*_test.go)
代码注释语言 中文
提交信息规范 统一固定格式,见 dev.md 第 2.4 节
特殊约定 注册制设计(中间件、模型、模块均可插拔注册);装配层编排生命周期;允许引入成熟第三方依赖

功能特性

  • 预制 Web 应用:tenon.NewWebApp 装配——主服务(HTTP/HTTPS/HTTP3(QUIC))恒定启动,可选模块按 Enable 清单加载,初始化失败自动逆序回滚
  • 装配层 app/:模块注册(RegisterModule)与启用(Enable)分离,自定义模块经 Custom 注册后按名启用;停机按初始化逆序释放
  • Web 服务:基于 gin,常规路由使用方法糖(GET/POST/.../ANY),Router 仅作动态/自定义方法逃生口,Engine()/Raw() 正式开放原生 gin 能力;支持 CORS、安全响应头、HTTPS 最低 TLS 版本配置、优雅停机与路由组
  • 启动可靠性:Start() 同步准备 HTTP/HTTPS/QUIC 监听,端口占用或证书错误直接返回,失败不留下部分监听;HTTPS/QUIC 随机端口保持一致,实例 Stop() 后不可重启
  • 信号停机:App.Run() / WebServer.Run() 在启动前订阅 SIGINT/SIGTERM,刚就绪即收到信号也能正常释放资源
  • 中间件注册制:tenon.RegisterMiddleware 注册后直接使用返回句柄;tenon.Middleware / tenon.HasMiddleware 仅用于配置驱动的按名查询(见 中间件用法)
  • 数据库模块:gorm 封装,支持 sqlite3 / mysql(可选 TLS 链路加密)、主从读写分离与多实例(InitNamed/Named),模型注册制自动迁移
  • Redis 模块:字符串/列表/集合/有序集合/哈希/Lua/原子轮换,支持 TLS、ACL 用户名与多实例(InitNamed/Named)
  • 日志模块:logrus + lumberjack 切割(log 模块)
  • 可选能力:requestid 模块注入 X-Request-Id;tenon.Bind 请求绑定工具(仅返回错误)
  • 统一响应封装与分页工具
  • 注册配置:模块通过 Default/Parse 声明同名配置段,独立管理器以 File.RegisterSection 按名注册声明;业务只读取 custom,无需总配置结构;启动永不写盘,缺文件提示先 tenon init
  • 显式配置命令:init(含调用方钩子)、config init/check/update/convert;强制覆盖先备份再替换并输出隐藏值的差异;加载、检查、更新及转换统一拒绝重复 JSON 键,避免未知数据丢失
  • JSON/TOML 由函数参数或 CLI --format json|toml 显式选择,缺省 JSON,不猜扩展名;JSON 时长保持纳秒,TOML 使用 30s 等可读字符串,转换保留未知字段,不能无损表示时拒绝
  • 保留泛型 LoadConfig 的版本参数签名与无文件程序化装配;新增 LoadConfigFormat / NewConfiguredWebAppFormat,配置管理器通过 WithFormat 选择格式
  • 内置 CLI:支持扩展自定义子命令(AddCommand/Add),Serve/Run 注册 server 子命令
  • 可复制服务端模板:example/server 集成 CLI、custom、日志、SQLite、鉴权与 CRUD,严格校验单个 JSON 正文;复制后源码零手写,显式修改 4 行配置即可启用,凭据仅从环境变量注入

快速开始

环境要求

  • Go 1.26+

安装与运行

go get gopkg.761sama.com/tenon

注册配置(推荐)

不定义总配置结构,内置模块自带默认值和解析函数;自定义业务字段放在 custom,详见 配置契约与命令。

package main

import (
	"github.com/gin-gonic/gin"
	"gopkg.761sama.com/tenon"
)

// 运行配置驱动服务。入参: 无;出参: 无,命令失败退出非零。
func main() {
	cli := tenon.NewCli("tenon", "我的服务")
	flags := cli.BindFlags()
	cli.WebApp(func() *tenon.WebApp {
		return tenon.NewConfiguredWebApp(flags.ConfigFile())
	}, func(a *tenon.WebApp) error {
		a.Server().GET("/ping", func(c *gin.Context) {
			tenon.Success(c, gin.H{"msg": "pong"})
		})
		return nil
	})
	cli.Execute()
}

可直接运行仓库示例:

go run ./example/config init
go run ./example/config config check
go run ./example/config server

TOML 使用 go run ./example/config --format toml init,默认文件为 data/config.toml。双向转换使用 config convert --to toml|json,源格式仍由 --format 指定;API 用法、精度限制与备份行为见 配置格式与转换。已有 JSON 调用无需修改。

生成的 data/config.json 中 enable 默认为 [],HTTP 必启,可选模块均不启动。按需编辑 enable(如 ["log", "database", "requestid"])及模块连接参数;配置升级使用显式 config update,而非启动时回写。

程序化装配(兼容,无需文件)

package main

import (
	"github.com/gin-gonic/gin"

	"gopkg.761sama.com/tenon"
)

func main() {
	application := tenon.NewWebApp(tenon.WebAppOptions{
		HTTP: tenon.DefaultHTTPConfig(),
		// 主服务(HTTP)恒定启动,无需声明;Enable 只列可选模块,顺序即初始化顺序
		Enable: []string{tenon.ModuleLog},
	})
	s := application.Server()
	s.GET("/ping", func(c *gin.Context) {
		tenon.Success(c, gin.H{"msg": "pong"})
	})
	if err := application.Run(); err != nil {
		panic(err)
	}
}

启用数据库与 Redis(配置非法时初始化失败并返回错误,未列出的模块完全不参与):

application := tenon.NewWebApp(tenon.WebAppOptions{
	HTTP: cfg.HTTP, Log: cfg.Log, Database: cfg.DB, Redis: cfg.Redis,
	Enable: []string{
		tenon.ModuleLog,
		tenon.ModuleDatabase,
		tenon.ModuleRedis,
		tenon.ModuleRequestID,
	},
})

手工装配(自由度)

不使用 WebApp 时,各模块仍可逐个显式初始化(与 WebApp 内部走的是同一套 Init):

package main

import (
	"github.com/gin-gonic/gin"

	"gopkg.761sama.com/tenon"
	"gopkg.761sama.com/tenon/web"
)

func main() {
	if err := tenon.InitLog(tenon.LogConfig{Enable: false}, false); err != nil {
		panic(err)
	}
	server, err := web.New(tenon.DefaultHTTPConfig())
	if err != nil {
		panic(err)
	}
	server.GET("/ping", func(c *gin.Context) {
		tenon.Success(c, gin.H{"msg": "pong"})
	})
	if err := server.Run(); err != nil {
		panic(err)
	}
}

数据库与 Redis 的手工显式初始化:

err := tenon.DB.Init(tenon.DatabaseConfig{Type: "sqlite3", Master: tenon.DBNodeConfig{DBFile: "data.db"}}, false)
tenon.DB.RegisterModels(new(User))
err = tenon.Redis.Init(tenon.RedisConfig{Host: "127.0.0.1", Port: 6379})

需要带数据库的正常服务端,直接复制 example/server/,按 模板使用与 curl 验收 初始化、显式启用模块并注入随机凭据。支持 JSON/TOML,无需外部数据库,不改变框架默认全禁用语义。

更多示例见 example/:basic(手工装配)、config(配置驱动)、cli(CLI)、app(完整 WebApp 用法)、server(可复制 SQLite 服务模板)。

项目结构

tenon.go / middleware.go / cli.go / webapp.go   框架门面(根包 tenon)
app/         装配层:模块注册表 + 启用清单 + 生命周期编排
conf/        配置结构、函数式声明、只读加载与显式文件管理
bootstrap/   资源释放注册表
logx/        日志模块(显式初始化)
database/    数据库模块(gorm,显式初始化)
redis/       Redis 模块(显式初始化)
web/         Web 服务(gin 引擎封装)
common/      统一响应、错误码、分页
example/     使用示例
doc/         详细文档

文档

  • 开发规范与 AI 工作流:见 dev.md
  • 详细文档:见 doc/(按主题拆分)
  • 装配层与模块启用清单:见 doc/app.md
  • 配置注册契约与命令:见 doc/config.md
  • 可复制服务端模板、独立模块构建与 curl 验收:见 doc/server.md
  • 框架设计与使用说明:见 doc/framework.md
  • 注册类 API 命名与注册/添加边界:见 注册类 API 一览
  • 原生 gin(Engine()/Raw()、静态文件、NoRoute、Handle):见 原生 gin

许可证

无