Solon Server 启动模式深度解析:从 0.3MB 内核到 10+ Server 插件 一、开篇Server 插件化设计哲学Java Web 开发中应用框架与底层服务器通常是强绑定的。你选了一个框架就绑定了它支持的服务器实现。切换往往意味着大量适配工作。Solon 的设计哲学不同业务代码与底层容器完全解耦。在 Solon 中你的 Controller、Service、Repository 等业务代码是不变的而底层服务器是可插拔的。只需要换一个 Maven 依赖就能从 JDK 内置 HTTP 服务器0.3MB切换到 Jetty2.7MB、Undertow4.6MB或 Vert.x6.3MB——业务代码零修改。这就是 Solon Server 插件化设计的核心价值维度传统方式Solon 方式框架与服务器关系强绑定可插拔切换服务器改代码/改配置换一个 Maven 依赖包大小通常较大按需选择最小 0.3MB协议支持通常只有 HTTPHTTP WebSocket Socket.D本文将带你深入解析 Solon 的 Server 启动模式体系。二、应用启动入口与生命周期2.1 标准启动方式所有 Solon 应用的入口都是Solon.start()SolonMain public class App { public static void main(String[] args) { Solon.start(App.class, args); } }2.2 带初始化函数的启动第三个参数是初始化函数在应用初始化时机点执行SolonMain public class App { public static void main(String[] args) { Solon.start(App.class, args, app - { // 控制信号启停、订阅早期事件等 app.enableHttp(true); app.enableWebSocket(true); }); } }2.3 应用生命周期全景Solon 应用的生命周期包含四个层次的时机点① 一个初始化函数时机点-Solon.start()的第三个参数回调② 六个应用事件时机点事件说明订阅方式AppInitEndEvent应用初始化完成只支持手动订阅AppPluginLoadEndEvent插件加载完成只支持手动订阅AppBeanLoadEndEventBean 扫描完成自动/手动AppLoadEndEvent应用启动完成自动/手动AppPrestopEndEvent应用预停止自动/手动AppStopEndEvent应用停止自动/手动③ 三个插件生命时机点public interface Plugin { void start(AppContext context) throws Throwable; default void prestop() throws Throwable {} default void stop() throws Throwable {} }④ 两个容器生命时机点-AppContext::start()— 扫描完成后执行 -AppContext::stop()— 插件 stop 后执行AppBeanLoadEndEvent之前的事件需要在启动前完成订阅否则会错过时机。三、启动参数体系3.1 完整参数表启动参数在应用启动后会被静态化启动后不可修改。启动参数对应配置描述--envsolon.env环境变量配置切换--scanning—是否扫描默认 1--debugsolon.debug调试模式0 或 1--setupsolon.setup安装模式0 或 1--whitesolon.white白名单模式0 或 1--driftsolon.drift漂移模式k8s 部署设为 1--alonesolon.alone单体模式0 或 1--extendsolon.extend扩展目录--localesolon.locale默认地区--config.addsolon.config.add增加外部配置--app.namesolon.app.name应用名--app.groupsolon.app.group应用分组--app.titlesolon.app.title应用标题--stop.safesolon.stop.safe安全停止0 或 1--stop.delaysolon.stop.delay安全停止延时秒数默认 103.2 三种等价写法所有带.的启动参数同时会成为应用配置以下三种写法完全等价# 方式一JVM 系统属性 java -Dsolon.envdev -jar demo.jar # 方式二完整的命令行参数 java -jar demo.jar --solon.envdev # 方式三简写命令行参数 java -jar demo.jar --envdev同理server.port也支持三种写法java -Dserver.port8081 -jar demo.jar java -jar demo.jar --server.port8081四、Server 插件全景矩阵Solon Server 系列包含所有通讯服务启动器插件。切换 Boot 插件只需更换 Maven/Gradle 依赖。4.1 HTTP 类 Server 插件插件框架版本包大小信号协议JDK要求开源协议solon-server-jdkhttpJDK0.3MBhttp8Apache 2.0solon-server-smarthttp [国产]—0.8MBhttp, ws8Apache 2.0solon-server-grizzly—1.8MBhttp, ws, http28EPL-2.0solon-server-vertx—6.3MBhttp, ws, http28EPL-2.0solon-server-jettyv92.7MBhttp, ws8EPL-2.0solon-server-jetty-jakartav123.9MBhttp, ws, http217EPL-2.0solon-server-undertowv2.24.6MBhttp, ws, http28Apache 2.0solon-server-undertow-jakartav2.3—http, ws, http217Apache 2.0solon-server-tomcatv9—http, ws, http28Apache 2.0solon-server-tomcat-jakartav11—http, ws, http217Apache 2.04.2 WebSocket 类 Server 插件插件包大小信号协议JDK要求开源协议solon-server-websocket0.4MBws8MITsolon-server-websocket-netty3.6MBws8Apache 2.04.3 Socket.D 类 Server 插件插件包大小信号协议JDK要求开源协议solon-server-socketd0.4MBtcp, udp, ws8Apache 2.04.4 插件切换方法切换 Boot 插件只需更换依赖业务代码无需任何修改!-- 替换前使用 JDK 内置 HTTP 服务器0.3MB -- dependency groupIdorg.noear/groupId artifactIdsolon-server-jdkhttp/artifactId /dependency !-- 替换后使用 Jetty2.7MB支持 WebSocket -- dependency groupIdorg.noear/groupId artifactIdsolon-server-jetty/artifactId /dependency4.5 二级扩展插件部分 Boot 插件有配套的二级插件按需添加Boot 插件二级插件说明solon-server-jettysolon-server-jetty-add-jsp增加 JSP 视图solon-server-jettysolon-server-jetty-add-websocket增加 WebSocketsolon-server-tomcatsolon-server-tomcat-add-jsp增加 JSP 视图solon-server-tomcatsolon-server-tomcat-add-websocket增加 WebSocketsolon-server-undertowsolon-server-undertow-add-jsp增加 JSP 视图五、HTTP 模式详解5.1 基础 Web 应用以最轻量的solon-server-jdkhttp0.3MB为例dependency groupIdorg.noear/groupId artifactIdsolon-server-jdkhttp/artifactId /dependency SolonMain public class DemoApp { public static void main(String[] args) { Solon.start(DemoApp.class, args); } } Controller public class DemoController { Mapping(/hello) public String hello(Param(defaultValue world) String name) { return Hello name !; } }5.2 SSL/HTTPS 配置方式一配置文件server: ssl: keyStore: /data/_ca/demo.jks # 或 demo.pfx keyPassword: demo方式二自定义 SSLContextv2.5.9不走配置文件完全代码控制SolonMain public class AppDemo { public static void main(String[] args) { Solon.start(AppDemo.class, args, app - { SSLContext sslContext buildSSLContext(); // 自行构建 app.onEvent(HttpServerConfigure.class, e - { e.enableSsl(true, sslContext); }); }); } }5.3 额外 HTTP 端口启用 HTTPS 后仍需保留 HTTP 端口的场景v2.2.18SolonMain public class SeverDemo { public static void main(String[] args) { Solon.start(SeverDemo.class, args, app - { app.onEvent(HttpServerConfigure.class, e - { e.addHttpPort(8082); }); }); } }5.4 控制端口启停// 关闭 HTTP 自动启动 SolonMain public class SeverDemo { public static void main(String[] args) { Solon.start(SeverDemo.class, args, app - { app.enableHttp(false); }); } }六、WebSocket 模式6.1 启用 WebSocket使用 Jetty 为例需添加二级插件dependency groupIdorg.noear/groupId artifactIdsolon-server-jetty/artifactId /dependency dependency groupIdorg.noear/groupId artifactIdsolon-server-jetty-add-websocket/artifactId /dependency SolonMain public class DemoApp { public static void main(String[] args) { Solon.start(DemoApp.class, args, app - { app.enableWebSocket(true); // 启用 WebSocket }); } }6.2 WebSocket 端点ServerEndpoint(/ws/demo/{id}) public class WebSocketDemo extends SimpleWebSocketListener { Override public void onMessage(WebSocket socket, String text) throws IOException { socket.send(我收到了 text); } Override public void onOpen(WebSocket socket) { System.out.println(连接建立 socket.param(id)); } }七、Socket.D 模式7.1 依赖配置dependency groupIdorg.noear/groupId artifactIdsolon-server-socketd/artifactId /dependency !-- 按需选择传输协议包 -- dependency groupIdorg.noear/groupId artifactIdsocketd-transport-netty/artifactId /dependency7.2 启用 Socket.D 服务SolonMain public class DemoApp { public static void main(String[] args) { Solon.start(DemoApp.class, args, app - { app.enableSocketD(true); }); } }7.3 Socket.D 端点ServerEndpoint(/demo/{id}) public class SocketDDemo extends SimpleListener { Override public void onMessage(Session session, Message message) throws IOException { session.send(test, new StringEntity(我收到了 message)); // session.param(id); // 获取路径变量 } }7.4 三种协议架构的端口分配协议端口计算示例server.socket.port28080sd:tcp${server.socket.port}28080sd:udp${server.socket.port} 128081sd:ws${server.socket.port} 2280827.5 Socket.D 配置项全表server: socket: name: waterapi.tcp # 信号名称 port: 28080 # 信号端口 host: 0.0.0.0 # 绑定主机 wrapPort: 28080 # 包装端口Docker 注册时用 wrapHost: 0.0.0.0 # 包装主机 coreThreads: 0 # 最小线程0自动 maxThreads: 0 # 最大线程0自动 idleTimeout: 0 # 闲置超时0自动ms ioBound: true # IO密集型八、Server 配置体系8.1 四大配置系列系列说明备注server.?主配置供信号配置继承server.http.?HTTP 信号配置—server.socket.?Socket 信号配置—server.websocket.?WebSocket 信号配置—8.2 配置继承关系当没有信号配置时使用主配置例如没有server.http.ssl时使用server.ssl端口默认值信号默认端口说明httpserver.port默认 8080主端口websocket主端口 1500023080socket主端口 20000280808.3 完整配置模板solon: app: name: demo group: demo env: dev stop: safe: 1 delay: 10 threads: virtual: enabled: false server: port: 8080 host: 0.0.0.0 # SSL 主配置所有信号共享 ssl: keyStore: /data/_ca/demo.jks keyPassword: demo # HTTP 信号配置 http: port: 8080 coreThreads: 0 maxThreads: 0 idleTimeout: 0 ioBound: true # WebSocket 信号配置 websocket: port: 23080 # Socket 信号配置 socket: name: demo.tcp port: 28080 host: 0.0.0.0 coreThreads: 0 maxThreads: 0 idleTimeout: 0 ioBound: true九、线程数配置9.1 配置项server: http: coreThreads: 0 # 最小线程0自动 maxThreads: 0 # 最大线程0自动 idleTimeout: 0 # 闲置超时ms ioBound: true # IO密集型 # 虚拟线程池v2.7.3 solon: threads: virtual: enabled: false9.2 自动计算规则IO 密集型ioBound: true默认配置项计算公式2c4g 实例coreThreadsCPU 内核数 × 24maxThreadscoreThreads × 32128CPU 密集型ioBound: false配置项计算公式2c4g 实例coreThreadsCPU 内核数 × 24maxThreadscoreThreads × 8329.3 调优建议coreThreads一般不需要配置BIO 太大不收缩NIO 不能太大maxThreads一般默认即可单实例且流量大或请求慢时适当调大线程数不是越多越好切换需要时间也不是越少越好会不够用Java 21 可考虑开启虚拟线程solon.threads.virtual.enabled: true十、嵌入式启动Solon 的所有 Server 插件均支持嵌入式启动可直接通过 Server 实现类手动控制生命周期// JDK HTTP Server JdkHttpServer server new JdkHttpServer(); server.start(null, 8080); // ... 使用中 server.stop(); // Jetty Server JettyServer server new JettyServer(); server.start(null, 8080); // Undertow Server UndertowServer server new UndertowServer(); server.start(null, 8080); // Vert.x Server VertxServer server new VertxServer(); server.start(null, 8080);这种模式适合 - 将 Solon 嵌入到已有 Java 应用中 - 在单元测试中启动轻量级服务器 - 构建自定义的启动流程十一、实战案例三种服务同时运行一个应用同时提供 HTTP API WebSocket Socket.D 三种服务11.1 Maven 依赖!-- HTTP WebSocket (通过 Jetty) -- dependency groupIdorg.noear/groupId artifactIdsolon-server-jetty/artifactId /dependency dependency groupIdorg.noear/groupId artifactIdsolon-server-jetty-add-websocket/artifactId /dependency !-- Socket.D -- dependency groupIdorg.noear/groupId artifactIdsolon-server-socketd/artifactId /dependency dependency groupIdorg.noear/groupId artifactIdsocketd-transport-netty/artifactId /dependency !-- 其他基础依赖 -- dependency groupIdorg.noear/groupId artifactIdsolon-web/artifactId /dependency11.2 配置文件server: port: 8080 http: port: 8080 coreThreads: 4 maxThreads: 128 websocket: port: 8080 # 与 http 共用端口 socket: name: demo.tcp port: 28080 coreThreads: 2 maxThreads: 6411.3 启动类SolonMain public class App { public static void main(String[] args) { Solon.start(App.class, args, app - { app.enableHttp(true); app.enableWebSocket(true); app.enableSocketD(true); }); } }11.4 HTTP 控制器Controller public class ApiGateway { Inject OrderService orderService; Mapping(/api/order/create) public OrderDTO createOrder(Body OrderRequest req) { return orderService.create(req); } Mapping(/api/order/{id}) public OrderDTO getOrder(int id) { return orderService.getById(id); } }11.5 WebSocket 端点ServerEndpoint(/ws/notify/{userId}) public class NotifyWebSocket extends SimpleWebSocketListener { Override public void onOpen(WebSocket socket) { String userId socket.param(userId); SessionManager.register(userId, socket); } Override public void onClose(WebSocket socket) { String userId socket.param(userId); SessionManager.unregister(userId); } Override public void onMessage(WebSocket socket, String text) { // 处理客户端推送的消息 } }11.6 Socket.D 端点ServerEndpoint(/sd/rpc) public class RpcSocketD extends SimpleListener { Override public void onMessage(Session session, Message message) throws IOException { if (order.query.equals(message.topic())) { String orderId message.bodyAsString(); // 处理 RPC 请求 session.reply(message, new StringEntity({\status\:\ok\})); } } }十二、总结与选型建议选型决策表场景推荐 Server 插件理由微服务 API、RESTfulsolon-server-jdkhttp0.3MB 极简够用需要 WebSocketsolon-server-jetty 或 solon-server-smarthttp原生 WS 支持高性能 HTTP/2solon-server-undertow 或 solon-server-vertxHTTP/2 支持传统 JSP 项目solon-server-tomcat JSP 二级插件JSP 兼容RPC 长连接solon-server-socketdSocket.D 协议最小化部署solon-server-jdkhttp0.3MB 包大小国产化/信创solon-server-smarthttp国产 HTTP 服务器核心要点业务代码与 Server 完全解耦— 只需换依赖代码零修改最小 0.3MB— jdkhttp 适合微服务和 Serverless三种信号并存— HTTP WebSocket Socket.D 可以同一应用运行配置继承— 信号配置缺省时自动使用主配置线程数自适应— 根据 CPU 内核数和 IO 类型自动计算嵌入式支持— 可以嵌入到已有 Java 应用中