Micronaut-Core:如何不使用@Endpoint注解创建动态端点
完全可以不使用@Endpoint注解创建动态端点,你可以借助Micronaut自带的路由注册API在应用启动时完成动态端点的加载,具体实现方案如下:
核心实现逻辑
你不需要依赖注解声明端点,直接注入Router和RouteBuilder两个核心组件,在启动事件触发、完成描述文件解析后,调用API注册路由即可:
import io.micronaut.context.event.StartupEvent import io.micronaut.context.event.ShutdownEvent import io.micronaut.runtime.event.annotation.EventListener import io.micronaut.web.router.Router import io.micronaut.web.router.RouteBuilder import io.micronaut.http.HttpRequest import io.micronaut.http.HttpResponse import io.micronaut.http.HttpMethod import io.micronaut.http.MediaType import jakarta.inject.Singleton import reactor.core.publisher.Mono import reactor.core.scheduler.Schedulers @Singleton class DynamicEndpointLoader( private val router: Router, private val routeBuilder: RouteBuilder ) { @EventListener internal fun onStartupEvent(event: StartupEvent) { // 1. 读取/resources下所有自定义描述文件 // 2. 调用你已开发完成的解析器,拿到所有解析后的MyDescription对象 val endpointConfigs: List<MyDescription> = yourParseLogic() endpointConfigs.forEach { config -> // 解析你配置里的HTTP方法、请求路径 val (method, path) = parseEndpointConfig(config.getEndpoint()) // 返回HttpMethod.GET、"/myapi/customendpoint/version"这类结果 // 注册路由 routeBuilder.addRoute( method, path, { _: HttpRequest<*> -> Mono.fromCallable { // 执行配置里的shell命令,拿到返回结果 val executeResult = runYourSshCommand(config.getCommand()) // 渲染输出模板,替换$RESULT变量 val output = config.getOutput().replace("\$RESULT", executeResult) // 返回响应 HttpResponse.ok(output).contentType(MediaType.APPLICATION_JSON) }.subscribeOn(Schedulers.boundedElastic()) // 阻塞的SSH操作放到IO线程池执行,避免占用Netty IO线程 } ).produces(MediaType.APPLICATION_JSON) } // 注册所有路由到运行时,立即生效 router.addRoutes(routeBuilder.build()) } @EventListener internal fun onShutdownEvent(event: ShutdownEvent) { // 按需实现路由卸载、资源释放逻辑 } }
注意事项
- 如果需要支持路径参数、请求参数匹配,
RouteBuilder也支持类似/myapi/{userId}/info的占位符写法,参数可以从HttpRequest对象中提取 - 建议给命令执行增加超时控制,避免请求长期挂起
- 可以根据需要为不同的动态端点设置不同的响应Content-Type、权限校验逻辑,只需要在处理函数中对应实现即可
内容的提问来源于stack exchange,提问作者Thraax.Session
相关产品推荐
相关产品推荐

