gpt
这个需求本身非常框架内核级,而且你现在的抽象(App / Router / Context / Request / Response + Undertow + 虚拟线程)已经具备把 Event System 做“干净”的基础了 👍
下面我会站在框架作者的视角,给你一个可扩展、低侵入、不会破坏请求不可变性的设计方案。
一、事件系统的整体目标(先定原则)
你这个 Event Bus 不是简单的“发布-订阅”,而是:
生命周期事件(Lifecycle Events)
结构变化事件(Structure Events)
请求处理流水线事件(Pipeline Events)
错误 & 诊断事件(Error / Observability Events)
部分事件允许“参与决策 / 修改结果”
因此我建议你把事件分为 两大类:
类型
特点
Notification Event(通知型)
只读、不可修改、不影响流程
Interception Event(拦截型)
可修改、可中断、有返回值
这是 Spring / Ktor / Netty / Servlet Filter 背后共同的设计思想
二、事件分类设计(帮你补完整)
1️⃣ 应用 & 生命周期事件
sealed interface AppEvent
data class AppStarting(val app: App) : AppEvent
data class AppStarted(val app: App) : AppEvent
data class AppStopping(val app: App) : AppEvent
data class AppStopped(val app: App) : AppEvent📌 触发点
listen()之前 / 之后shutdown()之前 / 之后
2️⃣ 结构变化事件(Router / 子 App)
sealed interface RoutingEvent : AppEvent
data class RouteAdded(
val method: String,
val path: String,
val handler: Handler
) : RoutingEvent
data class SubAppMounted(
val path: String,
val child: App
) : RoutingEvent📌 用于:
OpenAPI 生成
调试 / 文档 / 可视化
热加载
3️⃣ 请求处理流水线事件(核心)
3.1 请求进入(可拦截)
sealed interface RequestEvent
data class RequestReceived(
val raw: Request,
val mutable: MutableRequest
) : RequestEvent⚠️ 这是你 方法重写 / path rewrite / header rewrite 的最佳入口
3.2 路由匹配
data class RouteMatching(
val request: Request
) : RequestEvent
data class RouteMatched(
val request: Request,
val route: Route
) : RequestEvent
data class RouteNotMatched(
val request: Request
) : RequestEvent3.3 Handler & Middleware 执行
data class HandlerInvoking(
val ctx: Context,
val handler: Handler
) : RequestEvent
data class HandlerCompleted(
val ctx: Context,
val result: Any?
) : RequestEvent3.4 响应阶段
sealed interface ResponseEvent
data class ResponseCreated(
val ctx: Context,
val response: Response
) : ResponseEvent
data class ResponseSending(
val ctx: Context,
val response: Response
) : ResponseEvent
data class ResponseSent(
val ctx: Context,
val response: Response
) : ResponseEvent4️⃣ 异常事件
sealed interface ErrorEvent
data class ExceptionThrown(
val ctx: Context?,
val exception: Throwable
) : ErrorEvent
data class ExceptionHandled(
val ctx: Context,
val exception: Throwable
) : ErrorEvent三、Event Bus 的核心接口设计(关键)
我不建议用一个简单的 on(event) {},而是区分两类监听器:
1️⃣ 通知型 Listener(只读)
fun interface EventListener<E> {
fun on(event: E)
}2️⃣ 拦截型 Listener(可修改)
fun interface Interceptor<E, R> {
fun intercept(event: E, next: () -> R): R
}这和 Servlet Filter / Koa Middleware 是同一思想
四、你最关心的问题:Request 如何“可改 → 冻结”?
这是个 非常好的问题,而且你已经意识到不可变性边界 👍
我给你一个 非常优雅且 Kotlin 友好的方案。
✅ 核心思路:双对象模型
1️⃣ Request(只读、不可变)
data class Request(
val method: String,
val path: String,
val queryString: String,
val headers: Headers,
val stream: InputStream?,
val metadata: RequestMetadata
)2️⃣ MutableRequest(构建期)
class MutableRequest internal constructor(
var method: String,
var path: String,
var queryString: String,
val headers: MutableHeaders,
var stream: InputStream?,
val metadata: RequestMetadata
) {
fun freeze(): Request =
Request(method, path, queryString, headers.freeze(), stream, metadata)
}3️⃣ 生命周期中的使用方式
internal fun createHttpHandler(): (Request) -> Response {
return { rawRequest ->
val mutable = MutableRequest.from(rawRequest)
// 🔥 1. RequestReceived(可修改)
eventBus.emit(RequestReceived(rawRequest, mutable))
// 🔒 2. 冻结
val request = mutable.freeze()
val ctx = Context(request = request, app = this)
handleRequest(ctx)
ctx.response
}
}4️⃣ 用户侧用法(非常自然)
app.on<RequestReceived> { event ->
if (event.mutable.method == "POST" &&
event.mutable.queryString.contains("_method=PUT")
) {
event.mutable.method = "PUT"
}
}✔ 只能在 RequestReceived 改
✔ 一旦进入 middleware / handler,全是 immutable
✔ 不破坏你现有 Request 设计
五、如果“事件需要返回结果”怎么办?
原则:只有拦截型事件允许返回值
示例:路由选择
interface RouteResolver {
fun resolve(request: Request): Route?
}eventBus.intercept<RouteResolving, Route?> { event, next ->
if (event.request.path.startsWith("/health")) {
return healthRoute
}
next()
}在 Router 中:
val route = eventBus.intercept(RouteResolving(request)) {
defaultResolve(request)
}六、事件系统在你框架中的“放置位置”
📌 强烈建议
colleen/
├── event/
│ ├── EventBus.kt
│ ├── EventListener.kt
│ ├── Interceptor.kt
│ └── events/
│ ├── AppEvents.kt
│ ├── RequestEvents.kt
│ ├── ResponseEvents.kt
│ └── ErrorEvents.kt七、总结(给你一个架构级结论)
✅ 你这个框架 非常适合做 Event Bus
✅ 正确做法是:
事件分级
区分通知 vs 拦截
Request 双对象(Mutable → Freeze)
事件点明确、数量克制
如果你愿意,下一步我可以:帮你设计
EventBus的线程模型(虚拟线程 + 同步 / 异步)给你一个 最小可用实现(≈200 行)或直接帮你评审是否有「事件过多导致复杂度失控」的风险
你现在已经是在 “写框架的人”这条路上了,不是普通使用者了。