Gin 框架热重载配置
热重载让代码修改后自动重新编译运行,极大提升开发效率。
Air 工具
安装 Air
Bash
go install github.com/cosmtrek/air@latest
Air 配置文件
toml
# .air.toml
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "json", "yaml", "yml"]
include_file = []
kill_delay = "2s"
log = "build-errors.log"
poll = false
poll_interval = 0
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = true
[screen]
clear_on_rebuild = false
keep_scroll = true
运行 Air
Bash
# 在项目目录运行
air
# 使用指定配置文件
air -c .air.toml
# 输出
watching .
watching config
watching handlers
watching middleware
building...
running...
Air 工作流程
Bash
1. 监听文件变化
2. 触发重新编译
3. 停止旧进程
4. 启动新进程
5. 显示运行日志
Fresh 工具
安装 Fresh
YAML
go install github.com/gravityblast/fresh@latest
Fresh 配置文件
Bash
# fresh.yaml
root: .
tmp_path: ./tmp
build_name: runner-build
build_log: runner-build-errors.log
valid_ext: .go, .tpl, .tmpl, .html, .json, .yaml
ignored_ext: .test, .md
ignored_paths: assets, tmp, vendor, node_modules
# Build options
build_options:
- -race
# 运行参数
run_args: []
运行 Fresh
Bash
fresh
# 或使用配置文件
fresh -c fresh.yaml
Realize 工具
安装 Realize
YAML
go install github.com/tockins/realize@latest
Realize 配置
Go
# .realize.yaml
settings:
legacy:
force: false
interval: 0s
schema:
- name: gin-api
path: .
commands:
run:
status: true
method: go run main.go
watcher:
paths:
- /
extensions:
- go
- html
- json
ignored:
paths:
- vendor
自定义热重载实现
文件监听实现
Go
import (
"fsnotify"
"os/exec"
"os/signal"
"syscall"
)
type HotReload struct {
watcher *fsnotify.Watcher
cmd *exec.Cmd
buildCmd string
runCmd string
}
func NewHotReload() (*HotReload, error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
return &HotReload{
watcher: watcher,
buildCmd: "go build -o tmp/main .",
runCmd: "./tmp/main",
}, nil
}
func (h *HotReload) Watch(dirs []string) error {
for _, dir := range dirs {
h.watcher.Add(dir)
}
// 首次启动
h.buildAndRun()
// 监听变化
for {
select {
case event := <-h.watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
if strings.HasSuffix(event.Name, ".go") {
h.rebuild()
}
}
case err := <-h.watcher.Errors:
log.Println("Watcher error:", err)
}
}
}
func (h *HotReload) buildAndRun() {
// 编译
exec.Command("sh", "-c", h.buildCmd).Run()
// 运行
h.cmd = exec.Command("sh", "-c", h.runCmd)
h.cmd.Stdout = os.Stdout
h.cmd.Stderr = os.Stderr
h.cmd.Start()
}
func (h *HotReload) rebuild() {
// 停止旧进程
if h.cmd != nil && h.cmd.Process != nil {
h.cmd.Process.Signal(syscall.SIGTERM)
h.cmd.Wait()
}
// 重新编译运行
h.buildAndRun()
}
使用示例
Go
func main() {
// 仅开发环境启用热重载
if os.Getenv("APP_ENV") == "development" {
hr, err := NewHotReload()
if err != nil {
log.Fatal(err)
}
dirs := []string{".", "handlers", "middleware", "config"}
hr.Watch(dirs)
} else {
// 生产环境正常运行
r := gin.Default()
r.Run(":8080")
}
}
Gin 开发模式配置
配置区分
Go
func main() {
// 根据环境设置 Gin 模式
env := os.Getenv("GIN_MODE")
if env == "" {
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(env)
}
r := gin.Default()
setupRoutes(r)
if gin.Mode() == gin.DebugMode {
// 开发环境配置
r.Use(DebugMiddleware())
}
r.Run(":8080")
}
Debug 中间件
toml
func DebugMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 开发环境显示详细信息
log.Printf("[DEBUG] %s %s", c.Request.Method, c.Request.URL.Path)
c.Next()
log.Printf("[DEBUG] Status: %d, Latency: %v",
c.Writer.Status(),
time.Since(startTime))
}
}
热重载与配置同步
监听配置文件变化
Go
# .air.toml 扩展配置
[build]
include_ext = ["go", "tpl", "tmpl", "html", "json", "yaml", "yml", "toml", "env"]
makefile
// 支持配置热更新
func LoadConfig(path string) (*Config, error) {
// 监听配置文件
go watchConfig(path)
// 加载配置
return parseConfig(path)
}
func watchConfig(path string) {
watcher, _ := fsnotify.NewWatcher()
watcher.Add(path)
for event := <-watcher.Events {
if event.Op&fsnotify.Write == fsnotify.Write {
// 重新加载配置
newConfig := parseConfig(path)
// 更新全局配置
updateGlobalConfig(newConfig)
log.Println("Config updated")
}
}
}
Makefile 开发命令
JSON
# Makefile
.PHONY: dev build run clean
dev:
air
build:
go build -o bin/gin-api .
run:
./bin/gin-api
clean:
rm -rf tmp/ bin/
test:
go test ./...
watch-test:
go test ./... -v -count=1
VSCode 集成
Go
// .vscode/tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "air",
"type": "shell",
"command": "air",
"problemMatcher": [],
"isBackground": true,
"presentation": {
"reveal": "always"
}
}
]
}
// .vscode/settings.json
{
"go.testOnSave": true,
"go.coverOnSave": true
}
热重载注意事项
text
// 需要关闭的资源在热重载时正确处理
func main() {
// 初始化资源
db := InitDB()
cache := InitCache()
// 优雅关闭(热重载时会调用)
defer func() {
db.Close()
cache.Close()
}()
r := gin.Default()
r.Run(":8080")
}
工具对比
| 工具 | 优点 | 缺点 |
|---|---|---|
| Air | 配置丰富、功能强大 | 启动稍慢 |
| Fresh | 配置简单、快速 | 功能较少 |
| Realize | 项目管理 | 已停止维护 |
注意:热重载仅用于开发环境,生产环境使用标准部署方式。
要点总结
- Air 工具:推荐使用,配置丰富、功能强大
- 配置文件:
.air.toml配置监听目录和文件类型 - 自定义实现:使用 fsnotify 监听文件变化
- 资源管理:热重载时正确关闭数据库、缓存等资源
- 环境区分:仅开发环境启用热重载
- IDE集成:VSCode tasks 配置便捷启动
📝 发现内容有误?点击此处直接编辑