Skip to content

生命周期

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 阶段处理。

基于 Apache-2.0 许可证发布