
























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 启动模式体系。
所有 Solon 应用的入口都是 Solon.start():
@SolonMain
public class App {
public static void main(String[] args) {
Solon.start(App.class, args);
}
}
第三个参数是初始化函数,在应用初始化时机点执行:
@SolonMain
public class App {
public static void main(String[] args) {
Solon.start(App.class, args, app -> {
// 控制信号启停、订阅早期事件等
app.enableHttp(true);
app.enableWebSocket(true);
});
}
}
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之前的事件需要在启动前完成订阅,否则会错过时机。
启动参数在应用启动后会被静态化(启动后不可修改)。
| 启动参数 | 对应配置 | 描述 |
|---|---|---|
--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) |
所有带 . 的启动参数同时会成为应用配置,以下三种写法完全等价:
# 方式一: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
Solon Server 系列包含所有通讯"服务启动器"插件。切换 Boot 插件只需更换 Maven/Gradle 依赖。
| 插件 | 框架版本 | 包大小 | 信号协议 | 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 |
| 插件 | 包大小 | 信号协议 | JDK要求 | 开源协议 |
|---|---|---|---|---|
solon-server-websocket |
0.4MB | ws | 8+ | MIT |
solon-server-websocket-netty |
3.6MB | ws | 8+ | Apache 2.0 |
| 插件 | 包大小 | 信号协议 | JDK要求 | 开源协议 |
|---|---|---|---|---|
solon-server-socketd |
0.4MB | tcp, udp, ws | 8+ | Apache 2.0 |
切换 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>
部分 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 视图 |
以最轻量的 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 + "!";
}
}
方式一:配置文件
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);
});
});
}
}
启用 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);
});
});
}
}
// 关闭 HTTP 自动启动
@SolonMain
public class SeverDemo {
public static void main(String[] args) {
Solon.start(SeverDemo.class, args, app -> {
app.enableHttp(false);
});
}
}
使用 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
});
}
}
@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"));
}
}
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-server-socketd</artifactId>
</dependency>
<!-- 按需选择传输协议包 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>socketd-transport-netty</artifactId>
</dependency>
@SolonMain
public class DemoApp {
public static void main(String[] args) {
Solon.start(DemoApp.class, args, app -> {
app.enableSocketD(true);
});
}
}
@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"); // 获取路径变量
}
}
| 协议 | 端口计算 | 示例(server.socket.port=28080) |
|---|---|---|
sd:tcp |
${server.socket.port} |
28080 |
sd:udp |
${server.socket.port} + 1 |
28081 |
sd:ws |
${server.socket.port} + 2 |
28082 |
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.? |
主配置 | 供信号配置继承 |
server.http.? |
HTTP 信号配置 | — |
server.socket.? |
Socket 信号配置 | — |
server.websocket.? |
WebSocket 信号配置 | — |
server.http.ssl 时,使用 server.ssl端口默认值:
| 信号 | 默认端口 | 说明 |
|---|---|---|
| http | server.port(默认 8080) |
主端口 |
| websocket | 主端口 + 15000 | 23080 |
| socket | 主端口 + 20000 | 28080 |
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
server:
http:
coreThreads: 0 # 最小线程(0=自动)
maxThreads: 0 # 最大线程(0=自动)
idleTimeout: 0 # 闲置超时(ms)
ioBound: true # IO密集型
# 虚拟线程池(v2.7.3+)
solon:
threads:
virtual:
enabled: false
IO 密集型(ioBound: true,默认)
| 配置项 | 计算公式 | 2c4g 实例 |
|---|---|---|
| coreThreads | CPU 内核数 × 2 | 4 |
| maxThreads | coreThreads × 32 | 128 |
CPU 密集型(ioBound: false)
| 配置项 | 计算公式 | 2c4g 实例 |
|---|---|---|
| coreThreads | CPU 内核数 × 2 | 4 |
| maxThreads | coreThreads × 8 | 32 |
coreThreads 一般不需要配置(BIO 太大不收缩,NIO 不能太大)maxThreads 一般默认即可;单实例且流量大或请求慢时适当调大solon.threads.virtual.enabled: trueSolon 的所有 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);
这种模式适合:
一个应用同时提供 HTTP API + WebSocket + Socket.D 三种服务:
<!-- 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>
server:
port: 8080
http:
port: 8080
coreThreads: 4
maxThreads: 128
websocket:
port: 8080 # 与 http 共用端口
socket:
name: "demo.tcp"
port: 28080
coreThreads: 2
maxThreads: 64
@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);
});
}
}
@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);
}
}
@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) {
// 处理客户端推送的消息
}
}
@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 服务器 |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。