Solon Server 启动模式深度解析:从 0.3MB 内核到 10+ Server 插件

一、开篇:Server 插件化设计哲学

Java Web 开发中,应用框架与底层服务器通常是强绑定的。你选了一个框架,就绑定了它支持的服务器实现。切换?往往意味着大量适配工作。

Solon 的设计哲学不同:业务代码与底层容器完全解耦。

在 Solon 中,你的 Controller、Service、Repository 等业务代码是"不变的",而底层服务器是"可插拔的"。只需要换一个 Maven 依赖,就能从 JDK 内置 HTTP 服务器(0.3MB)切换到 Jetty(2.7MB)、Undertow(4.6MB)或 Vert.x(6.3MB)------业务代码零修改。

这就是 Solon Server 插件化设计的核心价值:

维度 传统方式 Solon 方式
框架与服务器关系 强绑定 可插拔
切换服务器 改代码/改配置 换一个 Maven 依赖
包大小 通常较大 按需选择,最小 0.3MB
协议支持 通常只有 HTTP HTTP + 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 插件加载完成 只支持手动订阅
AppBeanLoadEndEvent Bean 扫描完成 自动/手动
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 完整参数表

启动参数在应用启动后会被静态化(启动后不可修改)。

启动参数 对应配置 描述
--env solon.env 环境变量(配置切换)
--scanning --- 是否扫描(默认 1)
--debug solon.debug 调试模式(0 或 1)
--setup solon.setup 安装模式(0 或 1)
--white solon.white 白名单模式(0 或 1)
--drift solon.drift 漂移模式(k8s 部署设为 1)
--alone solon.alone 单体模式(0 或 1)
--extend solon.extend 扩展目录
--locale solon.locale 默认地区
--config.add solon.config.add 增加外部配置
--app.name solon.app.name 应用名
--app.group solon.app.group 应用分组
--app.title solon.app.title 应用标题
--stop.safe solon.stop.safe 安全停止(0 或 1)
--stop.delay solon.stop.delay 安全停止延时秒数(默认 10)

3.2 三种等价写法

所有带 . 的启动参数同时会成为应用配置,以下三种写法完全等价:

复制代码
# 方式一:JVM 系统属性
java -Dsolon.env=dev -jar demo.jar

# 方式二:完整的命令行参数
java -jar demo.jar --solon.env=dev

# 方式三:简写命令行参数
java -jar demo.jar --env=dev

同理,server.port 也支持三种写法:

复制代码
java -Dserver.port=8081 -jar demo.jar
java -jar demo.jar --server.port=8081

四、Server 插件全景矩阵

Solon Server 系列包含所有通讯"服务启动器"插件。切换 Boot 插件只需更换 Maven/Gradle 依赖。

4.1 HTTP 类 Server 插件

插件 框架版本 包大小 信号协议 JDK要求 开源协议
solon-server-jdkhttp JDK 0.3MB http 8+ Apache 2.0
solon-server-smarthttp 国产 --- 0.8MB http, ws 8+ Apache 2.0
solon-server-grizzly --- 1.8MB http, ws, http2 8+ EPL-2.0
solon-server-vertx --- 6.3MB http, ws, http2 8+ EPL-2.0
solon-server-jetty v9 2.7MB http, ws 8+ EPL-2.0
solon-server-jetty-jakarta v12 3.9MB http, ws, http2 17+ EPL-2.0
solon-server-undertow v2.2 4.6MB http, ws, http2 8+ Apache 2.0
solon-server-undertow-jakarta v2.3 --- http, ws, http2 17+ Apache 2.0
solon-server-tomcat v9 --- http, ws, http2 8+ Apache 2.0
solon-server-tomcat-jakarta v11 --- http, ws, http2 17+ Apache 2.0

4.2 WebSocket 类 Server 插件

插件 包大小 信号协议 JDK要求 开源协议
solon-server-websocket 0.4MB ws 8+ MIT
solon-server-websocket-netty 3.6MB ws 8+ Apache 2.0

4.3 Socket.D 类 Server 插件

插件 包大小 信号协议 JDK要求 开源协议
solon-server-socketd 0.4MB tcp, udp, ws 8+ Apache 2.0

4.4 插件切换方法

切换 Boot 插件只需更换依赖,业务代码无需任何修改:

复制代码
<!-- 替换前:使用 JDK 内置 HTTP 服务器(0.3MB) -->
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jdkhttp</artifactId>
</dependency>

<!-- 替换后:使用 Jetty(2.7MB,支持 WebSocket) -->
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jetty</artifactId>
</dependency>

4.5 二级扩展插件

部分 Boot 插件有配套的二级插件,按需添加:

Boot 插件 二级插件 说明
solon-server-jetty solon-server-jetty-add-jsp 增加 JSP 视图
solon-server-jetty solon-server-jetty-add-websocket 增加 WebSocket
solon-server-tomcat solon-server-tomcat-add-jsp 增加 JSP 视图
solon-server-tomcat solon-server-tomcat-add-websocket 增加 WebSocket
solon-server-undertow solon-server-undertow-add-jsp 增加 JSP 视图

五、HTTP 模式详解

5.1 基础 Web 应用

以最轻量的 solon-server-jdkhttp(0.3MB)为例:

复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-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"

方式二:自定义 SSLContext(v2.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.18+):

复制代码
@SolonMain
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>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jetty</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-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>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-socketd</artifactId>
</dependency>
<!-- 按需选择传输协议包 -->
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>socketd-transport-netty</artifactId>
</dependency>

7.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.port=28080)
sd:tcp ${server.socket.port} 28080
sd:udp ${server.socket.port} + 1 28081
sd:ws ${server.socket.port} + 2 28082

7.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

端口默认值:

信号 默认端口 说明
http server.port(默认 8080) 主端口
websocket 主端口 + 15000 23080
socket 主端口 + 20000 28080

8.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: false

9.2 自动计算规则

IO 密集型(ioBound: true,默认)

配置项 计算公式 2c4g 实例
coreThreads CPU 内核数 × 2 4
maxThreads coreThreads × 32 128

CPU 密集型(ioBound: false)

配置项 计算公式 2c4g 实例
coreThreads CPU 内核数 × 2 4
maxThreads coreThreads × 8 32

9.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>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jetty</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jetty-add-websocket</artifactId>
</dependency>

<!-- Socket.D -->
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-socketd</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>socketd-transport-netty</artifactId>
</dependency>

<!-- 其他基础依赖 -->
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-web</artifactId>
</dependency>

11.2 配置文件

复制代码
server:
  port: 8080
  
  http:
    port: 8080
    coreThreads: 4
    maxThreads: 128
  
  websocket:
    port: 8080    # 与 http 共用端口
  
  socket:
    name: "demo.tcp"
    port: 28080
    coreThreads: 2
    maxThreads: 64

11.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、RESTful solon-server-jdkhttp 0.3MB 极简,够用
需要 WebSocket solon-server-jetty 或 solon-server-smarthttp 原生 WS 支持
高性能 HTTP/2 solon-server-undertow 或 solon-server-vertx HTTP/2 支持
传统 JSP 项目 solon-server-tomcat + JSP 二级插件 JSP 兼容
RPC 长连接 solon-server-socketd Socket.D 协议
最小化部署 solon-server-jdkhttp 0.3MB 包大小
国产化/信创 solon-server-smarthttp 国产 HTTP 服务器

核心要点

  1. 业务代码与 Server 完全解耦 --- 只需换依赖,代码零修改
  2. 最小 0.3MB --- jdkhttp 适合微服务和 Serverless
  3. 三种信号并存 --- HTTP + WebSocket + Socket.D 可以同一应用运行
  4. 配置继承 --- 信号配置缺省时自动使用主配置
  5. 线程数自适应 --- 根据 CPU 内核数和 IO 类型自动计算
  6. 嵌入式支持 --- 可以嵌入到已有 Java 应用中
相关推荐
悟空码字26 分钟前
视频号直播变了
微信·视频号
熊思宇6 小时前
必应关闭今日热点
其他
nington0112 小时前
金融信创国产AD重构:2027倒计时下的技术选型与落地路径
其他·1024程序员节
JiNan.YouQuan.Soft1 天前
Windows下编译CGMA
其他·1024程序员节
AMASENSYS艾马斯1 天前
变频器过载能力参数解读与工程应用
驱动开发·嵌入式硬件·其他·硬件工程·精益工程
Yurko131 天前
原码、反码、补码的快速学习
笔记·学习·其他
随性而行3601 天前
企业微信 Webhook 接收不到消息?网络连通性、URL 签名验签与 API 返回错误码排查指南
java·网络·人工智能·后端·微信·企业微信
打螺丝的小李2 天前
企业已经上了ERP和MES,还需不需要再单独上一套QMS?
其他
未秃头的程序猿2 天前
同一个商户号,V2 免密代扣和 V3 分账的证书怎么共存?
java·后端·微信
木易 士心2 天前
Spring Boot 微信公众号后端服务开发实战指南
spring boot·后端·微信