第 1 章 第一个 Owl 应用:5 分钟跑通
本文导航

第 1 章 第一个 Owl 应用:5 分钟跑通
这一章只做一件事:用最少的代码把 Owl 服务启动起来,并成功访问一个接口。先建立「它真的能跑」的信心,再去理解内部机制。
环境准备
- Go 版本以
owl/go.mod为准(当前声明go 1.26.0); - 新建一个空目录,例如
my-order; - 本地已有
owl/仓库。
1. 初始化模块
mkdir my-order && cd my-order
go mod init my-order
在 go.mod 里引用本地框架:
module my-order
go 1.26.0
require bit-labs.cn/owl v0.0.0
replace bit-labs.cn/owl => ../owl
replace只用于本地联调。发布时改用正式版本号,并删掉replace。
2. 写入口
// main.go
package main
import (
"bit-labs.cn/owl"
"my-order/app"
)
func main() {
owl.NewApp(&app.SubAppOrder{}).WebShell()
}
NewApp 收集子应用,WebShell 负责装配并启动 HTTP 服务。命令行模式则用 ConsoleShell,见第 2 章。
3. 写子应用
// app/app.go
package app
import (
"bit-labs.cn/owl"
"bit-labs.cn/owl/contract/foundation"
"bit-labs.cn/owl/provider/db"
"bit-labs.cn/owl/provider/router"
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
"gorm.io/gorm"
)
var _ owl.SubApp = (*SubAppOrder)(nil)
type SubAppOrder struct {
// 字段名必须是 app,框架用反射注入
app foundation.Application
}
func (i *SubAppOrder) Name() string { return "order" }
func (i *SubAppOrder) ServiceProviders() []foundation.ServiceProvider {
return []foundation.ServiceProvider{
&router.RouterServiceProvider{},
&db.DBServiceProvider{},
}
}
func (i *SubAppOrder) RegisterRouters() {
// 本章先用最直接的方式注册一条路由
err := i.app.Invoke(func(engine *gin.Engine) {
engine.GET("/api/v1/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"success": true, "msg": "pong"})
})
})
owl.PanicIf(err)
}
func (i *SubAppOrder) Binds() []any { return nil }
func (i *SubAppOrder) Bootstrap() {}
func (i *SubAppOrder) RegisterMenus() []*router.Menu { return nil }
func (i *SubAppOrder) RegisterCommands() []*cobra.Command { return nil }
func (i *SubAppOrder) RegisterMigrate() []any { return nil }
func (i *SubAppOrder) BeforeMigrate(*gorm.DB) error { return nil }
func (i *SubAppOrder) AfterMigrate(*gorm.DB) error { return nil }
补上 gin 的 import(github.com/gin-gonic/gin)。
这里有三个必须注意的点:
SubAppOrder必须有名为app的字段,否则框架反射注入时会 panic。ServiceProviders()至少要有router.RouterServiceProvider,否则拿不到*gin.Engine。Binds()返回的是构造函数列表,不是实例;本章没有业务服务,所以返回nil。
4. 拉依赖并启动
go mod tidy
go run .
第一次启动时,框架会:
- 创建
conf/目录; - 根据各 Provider 的
Conf()生成conf/router.yaml、conf/database.yaml、conf/log.yaml等; - 读取配置、初始化日志、注册路由;
- 在
conf/router.yaml的server.host:port(默认0.0.0.0:8080)上监听。
看到类似下面的日志就说明服务起来了:
启动 HTTP 服务器 监听 0.0.0.0:8080
5. 验证
curl "http://127.0.0.1:8080/health"
curl "http://127.0.0.1:8080/api/v1/ping"
期望分别返回 {"status":"ok"} 和 {"success":true,"msg":"pong"}。
6. 先不用数据库
本章注册了 db.DBServiceProvider,但没有配置数据库。默认 conf/database.yaml 指向 PostgreSQL,如果本机没有数据库,启动阶段可能报连接错误。
最省事的做法是先用 SQLite:
# conf/database.yaml
driver: sqlite
host: my-order.db
database: main
SQLite 模式下,数据库文件会放在 conf/ 目录下(框架把 host 拼到配置目录)。
如果你暂时只想验证 HTTP,也可以先移除 db.DBServiceProvider,下一章再按需加回。
7. 这一章你完成了什么
- 建立了
main.go + app/的最小结构; - 让框架自动生成了配置;
- 启动了一个真实的 Gin 服务;
- 用一条路由验证了 HTTP 链路。
下一章会把这条链路拆开,说明从 NewApp 到 WebShell 每一步的执行顺序,以及为什么配置必须先落盘、再注册 Provider。
自检
- [ ] 服务能启动且不 panic;
- [ ]
conf/目录已自动生成; - [ ]
/health与/api/v1/ping都能访问; - [ ] 能说出
app字段和ServiceProviders()各自的作用。
暂无上一篇
下一篇 第 2 章 应用生命周期:从 NewApp 到 WebShell
评论
加载评论中…