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()

java 复制代码
@SolonMain
public class App {
    public static void main(String[] args) {
        Solon.start(App.class, args);
    }
}

2.2 带初始化函数的启动

第三个参数是初始化函数,在应用初始化时机点执行:

java 复制代码
@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 应用停止 自动/手动

③ 三个插件生命时机点

java 复制代码
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 三种等价写法

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

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

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

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

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

bash 复制代码
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 插件只需更换依赖,业务代码无需任何修改:

xml 复制代码
<!-- 替换前:使用 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)为例:

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jdkhttp</artifactId>
</dependency>
java 复制代码
@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 配置

方式一:配置文件

yaml 复制代码
server:
  ssl:
    keyStore: "/data/_ca/demo.jks"    # 或 "demo.pfx"
    keyPassword: "demo"

方式二:自定义 SSLContext(v2.5.9+)

不走配置文件,完全代码控制:

java 复制代码
@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+):

java 复制代码
@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 控制端口启停

java 复制代码
// 关闭 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 为例(需添加二级插件):

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jetty</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-server-jetty-add-websocket</artifactId>
</dependency>
java 复制代码
@SolonMain
public class DemoApp {
    public static void main(String[] args) {
        Solon.start(DemoApp.class, args, app -> {
            app.enableWebSocket(true);  // 启用 WebSocket
        });
    }
}

6.2 WebSocket 端点

java 复制代码
@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 依赖配置

xml 复制代码
<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 服务

java 复制代码
@SolonMain
public class DemoApp {
    public static void main(String[] args) {
        Solon.start(DemoApp.class, args, app -> {
            app.enableSocketD(true);
        });
    }
}

7.3 Socket.D 端点

java 复制代码
@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 配置项全表

yaml 复制代码
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 完整配置模板

yaml 复制代码
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 配置项

yaml 复制代码
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 实现类手动控制生命周期:

java 复制代码
// 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 依赖

xml 复制代码
<!-- 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 配置文件

yaml 复制代码
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 启动类

java 复制代码
@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 控制器

java 复制代码
@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 端点

java 复制代码
@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 端点

java 复制代码
@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-jettysolon-server-smarthttp 原生 WS 支持
高性能 HTTP/2 solon-server-undertowsolon-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 应用中
相关推荐
郝学胜-神的一滴1 小时前
干货版《算法导论》07:递归视角下的选择排序与归并排序
java·数据结构·c++·python·程序人生·算法·排序算法
掉鱼的猫1 小时前
Solon Server 启动模式深度解析:从 0.3MB 内核到 10+ Server 插件
java·http
shehuiyuelaiyuehao1 小时前
多线程入门
java·python·算法
星夜夏空991 小时前
FreeRTOS学习(7)——任务列表
java·前端·学习
han_hanker2 小时前
BeanUtils.copyProperties 和序列化的问题
java·开发语言·spring boot
野生技术架构师2 小时前
牛客网2026互联网大厂Java面试题汇总,附官方级答案解析
java·开发语言
AZaLEan__2 小时前
多源 BFS
java·开发语言·算法
程序员卷卷狗3 小时前
Java转Go面试速记:Go基础22问,一篇理清高频易错点一篇理清高频易错点
java·面试·golang
zzzzz3693 小时前
快速搭建SpringAi项目 集成智能问答,RAG,FUINCTION_CALLING等功能
java·ai编程