生命周期
ACE Framework 定义了清晰的应用生命周期:从配置加载、Bean 注册、数据库初始化、调度器启动,直到监听端口;终止时按反向顺序优雅清理资源。理解这条链路有助于正确放置初始化逻辑和资源释放代码。
启动流程
AceApplication.runWithArgs(args)
│
▼
1. 加载配置(ace.yaml + 环境覆盖)
│
▼
2. 执行自注册代码(__ace_reg_* 初始化器)
── 所有 @Service / @Controller 完成注册
│
▼
3. 解析依赖图 & 注入字段
── 检测循环依赖,发现则 panic
│
▼
4. OrmComponent 建表(DDL auto-create)
│
▼
5. 调用所有 @PostConstruct 方法
│
▼
6. startScheduler(@Scheduled 任务入队)
│
▼
7. listen(app, host, port) ← 开始接受请求AceApplication.runWithArgs
runWithArgs 是标准入口,接收命令行参数并驱动完整启动链:
cangjie
package com.example
import ace.framework.*
func main(args: Array<String>): Unit {
AceApplication.runWithArgs(args)
}支持的命令行参数:
| 参数 | 示例 | 说明 |
|---|---|---|
--env | --env prod | 指定运行环境,影响 @Profile 装配和配置文件合并 |
--port | --port 9090 | 覆盖 ace.yaml 中的监听端口 |
--config | --config /etc/app.yaml | 指定外部配置文件路径 |
bash
# 以生产环境、9090 端口启动
./my-app --env prod --port 9090@PostConstruct
@PostConstruct 标注的方法在 Bean 被 IoC 容器首次 resolve 并完成字段注入后调用一次(Singleton 只调用一次,Prototype 每次 resolve 都调用)。适合执行需要依赖已就绪的初始化逻辑:
cangjie
@Service
class CacheWarmer {
@Inject
var db!: Database
@Inject
var cache!: CacheProvider
@PostConstruct
func warmUp(): Unit {
// 此时 db 和 cache 均已注入完毕
let hot = db.query("SELECT * FROM products WHERE hot = true")
for (p in hot) {
cache.set("product:${p.id}", p, ttl: 3600)
}
println("Cache warmed: ${hot.size} products loaded")
}
}Singleton 保证
对于 @Service(Singleton)Bean,@PostConstruct 方法在整个应用生命周期中只执行一次,即使多个地方同时 resolve 该 Bean 也不会重复执行(内部有一次性守卫)。
@PreDestroy
@PreDestroy 标注的方法在应用关闭时(优雅停机流程中)被调用,适合释放资源、关闭连接、刷写缓冲:
cangjie
@Service
class DatabasePool {
var connections: ArrayList<Connection> = ArrayList()
@PostConstruct
func init(): Unit {
for (_ in 0..10) {
connections.add(openConnection())
}
}
@PreDestroy
func close(): Unit {
for (conn in connections) {
conn.close()
}
println("All DB connections closed")
}
}调用顺序
多个 Bean 的 @PreDestroy 按依赖关系反序调用:被依赖的 Bean 最后销毁,确保其他 Bean 销毁时依赖仍可用。
优雅停机
当收到 SIGINT(Ctrl-C)或 SIGTERM 信号时,ACE Framework 执行以下停机序列:
收到 SIGINT / SIGTERM
│
▼
1. 停止接受新请求(关闭监听套接字)
│
▼
2. 等待在途请求完成(最长等待 gracefulTimeout,默认 30s)
│
▼
3. stopScheduler(等待运行中的 @Scheduled 任务结束)
│
▼
4. 依次调用所有 Bean 的 @PreDestroy 方法(反依赖序)
│
▼
5. 进程退出(exit code 0)可通过配置调整优雅停机超时:
yaml
# ace.yaml
ace:
server:
graceful-timeout: 60000 # 毫秒,默认 30000完整示例
以下展示一个带完整生命周期钩子的应用:
cangjie
package com.example
import ace.framework.*
import ace.web.*
// Bean:初始化与销毁
@Service
class AppMetrics {
var requestCount: Int64 = 0
@PostConstruct
func start(): Unit {
println("[Metrics] initialized")
}
@PreDestroy
func flush(): Unit {
println("[Metrics] total requests: ${requestCount}")
// 将指标写入持久存储
}
}
// 控制器:使用 metrics
@Controller["/api"]
class ApiController {
@Inject
var metrics!: AppMetrics
@Get["/ping"]
func ping(): String {
metrics.requestCount++
return "pong"
}
}
// 入口
func main(args: Array<String>): Unit {
AceApplication.runWithArgs(args)
// runWithArgs 会阻塞直到进程终止
}bash
# 启动
./my-app --env dev --port 8080
# 输出示例
[Metrics] initialized
[ACE] Listening on 0.0.0.0:8080
# 按 Ctrl-C
[ACE] Graceful shutdown initiated...
[ACE] Waiting for 0 in-flight requests...
[Metrics] total requests: 42
[ACE] Shutdown complete避免在 @PreDestroy 中执行耗时操作
@PreDestroy 方法的总执行时间受 graceful-timeout 限制。超时后进程将被强制终止(SIGKILL),未完成的清理逻辑将被跳过。资源释放应尽量轻量,耗时操作(如等待远程 ACK)应在 stopScheduler 阶段处理。