概述
在梳理JVM生态下Web开发框架:SparkJava、Javalin、Micronaut、SparkKotlin时,发现国产也有一款框架Solon,参考网络资料,记录一下学习心得。
官网,面向Java开发者、纯Java实现、开源(GitHub,2.8K Star,287 Fork;Gitee,4.3K Star,780 Fork;)Web开发框架、参考Spring Boot和Javalin设计,吸取两者优点,避开繁重设计,同时支持HTTP、WebSocket、Socket三种接入。官方文档。
对标美国博通公司(Broadcom)的Spring生态:并发高700%;内存省50%;启动快10倍;打包小90%;同时支持JDK8~JDK26,原生运行。参考三方性能压测数据。
设计思路:
- AOP:更偏向于显示的声明
- 容器处理:只有两个核心,Plugin组件+Bean加载
- IOC:简化
使用建议:
- 适合处理非核心业务的新项目,使用无压力 ,文档丰富,没什么太大难度
- 参考Spring,对整个流程进行极大简化 ,出问题基本上可通过读源码解决
- 性能和内存占用:会有明显提升
- 不适合改造旧项目 ,难度太大
简介
| 代码仓库 | 描述 |
|---|---|
/opensolon/solon |
主仓库 |
/opensolon/solon-examples |
官网配套示例代码 |
/opensolon/solon-ai |
Solon AI |
/opensolon/solon-flow |
Solon Flow |
/opensolon/solon-expression |
Solon表达式 |
/opensolon/solon-cloud |
Solon Cloud |
/opensolon/solon-admin |
Solon Admin |
/opensolon/solon-integration |
Solon 集成 |
/opensolon/solon-java17 |
Solon适配Java17 |
/opensolon/solon-java25 |
Solon适配Java25 |
/opensolon/soloncode |
SolonCode,Claude Code JDK8实现版 |
/opensolon/solonclaw |
SolonClaw,OpenClaw JDK8实现版 |
/opensolon/solon-maven-plugin |
Solon Maven插件 |
/opensolon/solon-gradle-plugin |
Solon Gradle插件 |
/opensolon/solon-idea-plugin |
Solon IDEA插件 |
/opensolon/solon-vscode-plugin |
Solon VS Code插件 |
架构图

Solon Cloud:简称SC,和上面的Solon还是有一些差别的

优点
- 更小、更快、更自由
- 支持注解与手动两种模式,按需自由操控
- 自带IOC&AOP容器,支持PRC、REST API、MVC开发
- 集合Handler+Context和Listener+Message两种架构模式;强调插件式扩展;适应不同的应用场景
- 统一Http、WebSocket、Socket三种信号的开发体验
- 插件可扩展可切换:启动插件,扩展插件,序列化插件,数据插件,会话状态插件,视图插件(可共存)等...
- 使用上与Spring Boot近似,迁移成本低
缺点
- 新框架的通病,用户实战笔记、文档较少(官方文档还是挺全面)
- 生态:第三方项目的适配较少
插件体系
Boot插件
| 插件 | 说明 |
|---|---|
org.noear:solon.boot.jlhttp* |
对jlhttp适配,提供HTTP服务(不自带session state) |
org.noear:solon.boot.jetty* |
对jetty适配,提供HTTP服务 |
org.noear:solon.boot.undertow* |
对undertow适配,提供HTTP、websocket服务 |
org.noear:solon.boot.websocket |
对java-websocket适配,提供websocket服务 |
org.noear:solon.boot.socketd.jdksocket |
对jdk-socket适配,提供socketd服务 |
org.noear:solon.boot.socketd.netty |
对netty适配,提供socketd服务 |
org.noear:solon.boot.socketd.rsocket |
对rsocket适配,提供socketd服务 |
org.noear:solon.boot.socketd.smartsocket |
对smartboot-socket适配,提供socketd服务 |
org.noear:solon.boot.socketd.websocket |
对java-websocket适配,提供socketd服务 |
扩展插件
| 插件 | 说明 |
|---|---|
org.noear:solon.extend.jetty.jsp |
为jetty添加jsp支持包(不建议使用) |
org.noear:solon.extend.jetty.websocket |
为jetty添加websoekct支持包 |
org.noear:solon.extend.undertow.jsp |
为undertow添加jsp支持(不建议使用) |
org.noear:solon.extend.staticfiles |
添加静态文件支持(监视resources/static文件夹 |
org.noear:solon.extend.aspect |
切面支持插件,添加Dao、Service注解支持;进而支持类的代理模式 |
org.noear:solon.extend.data |
数据操作支持,实现事务和缓存的注解支持 |
org.noear:solon.extend.validation |
验证操作支持插件,实现验证类注解支持 |
org.noear:solon.extend.properties.yaml |
Yaml配置支持插件,添加YML配置文件支持 |
org.noear:solon.extend.schedule |
定时任务支持插件,实现定时任务支持(和cron4j-solon-plugin风格不同 |
org.noear:solon.extend.stop |
远程关闭支持插件,实现远程关闭支持 |
org.noear:solon.extend.sessionstate.local |
可将Boot插件的Session State服务,替换为本地Session |
org.noear:solon.extend.sessionstate.redis |
分布式Session,其于Redis构建 |
org.noear:solon.extend.sessionstate.jwt |
分布式Session,其于JWT构建 |
序列化插件
| 插件 | 说明 |
|---|---|
org.noear:solon.serialization.fastjson* |
对fastjson适配,提供JSON视图输出或序列化输出 |
org.noear:solon.serialization.snack3* |
对snack3适配,提供JSON视图输出或序列化输出 |
org.noear:solon.serialization.jackson |
对jackson适配,提供JSON视图输出或序列化输出 |
org.noear:solon.serialization.hession* |
对hession适配,提供Hession序列化输出 |
org.noear:solon.serialization.protostuff* |
对protostuff适配,提供ProtoStuff序列化输出 |
视图插件:提供HTML视图输出,可配置多个视图插件
| 插件 | 说明 |
|---|---|
org.noear:solon.view.freemarker* |
对Freemarker适配 |
org.noear:solon.view.jsp |
对JSP适配 |
org.noear:solon.view.velocity |
对Velocity适配 |
org.noear:solon.view.thymeleaf |
对Thymeleaf适配 |
org.noear:solon.view.beetl |
对Beetl适配 |
org.noear:solon.view.enjoy |
对Enjoy适配 |
SpringBoot适配插件:org.noear:solon-springboot-starter
Solon第三方框架适配插件
| 插件 | 说明 |
|---|---|
org.noear:beetlsql-solon-plugin |
BeetlSQL适配插件 |
org.noear:mybatis-solon-plugin |
MyBatis适配插件 |
org.noear:mybatis-sqlhelper-solon-plugin |
MyBatis-SQLHelper适配插件 |
org.noear:weed3-solon-plugin |
Weed3适配插件 |
org.noear:cron4j-solon-plugin |
Cron4j适配插件 |
org.noear:quartz-solon-plugin |
Quartz适配插件 |
org.noear:dubbo-solon-plugin |
Dubbo适配插件 |
org.noear:feign-solon-plugin |
Feign适配插件 |
org.noear:hasor-solon-plugin |
Hasor适配插件 |
org.noear:luffy-solon-plugin |
Luffy适配插件 |
org.noear:sureness-solon-plugin |
Sureness适配插件 |
SC第三方框架适配插件
| 插件 | 说明 |
|---|---|
org.noear:consul-solon-plugin |
Consul适配(支持SC配置服务、注册与发现服务) |
org.noear:nacos-solon-plugin |
Nacos适配(同上) |
org.noear:zookeeper-solon-plugin |
Zookeeper适配(同上) |
org.noear:water-solon-plugin |
Water适配(支持SC配置服务、注册与发现服务、事件总线服务、日志服务、跟踪服务、锁服务) |
org.noear:rabbitmq-solon-plugin |
RabbitMQ适配(支持SC事件总线服务) |
org.noear:rocketmq-solon-plugin |
RocketMQ适配(同上) |
org.noear:mqtt-solon-plugin |
MQTT适配(同上) |
org.noear:kafka-solon-plugin |
Kafka适配(同上) |
org.noear:guava-solon-plugin |
Guava适配(支持SC融断服务) |
org.noear:sentinel-solon-plugin |
Sentinel适配(同上) |
org.noear:semaphore-solon-plugin |
Semaphore适配(同上) |
org.noear:aliyun-oss-solon-plugin |
Aliyun-OSS适配(支持SC分布式文件服务) |
org.noear:aws-s3-solon-plugin |
AWS-S3适配(同上) |
org.noear:snowflake-id-solon-plugin |
Snowflake算法适配插件(支持SC分布式ID服务) |
Nami框架(Remoting Client)
| 插件 | 说明(通道+编码器) |
|---|---|
org.noear:nami |
Nami内核(支持HTTP、Socket、WebSocket) |
org.noear:nami.channel.http.hutool |
HTTP通道 |
org.noear:nami.channel.http.okhttp |
HTTP通道 |
org.noear:nami.channel.socketd.jdksocket |
Socketd通道-基于BIO实现 |
org.noear:nami.channel.socketd.netty |
Socketd通道-基于NIO、Netty实现 |
org.noear:nami.channel.socketd.rsocket |
Socketd通道-基于RSocket实现 |
org.noear:nami.channel.socketd.smartsocket |
Socketd通道-基于AIO实现 |
org.noear:nami.channel.socketd.websocket |
Socketd通道-基于WebSocket实现 |
org.noear:nami.coder.fastjson |
JSON编码器 |
org.noear:nami.coder.hessian |
Hessian编码器 |
org.noear:nami.coder.jackson |
Jackson编码器 |
org.noear:nami.coder.protostuff |
ProtoStuff编码器 |
org.noear:nami.coder.snack3 |
JSON编码器 |
注解
使用@Tran注解来申明和管理事务,支持多数据源事务。
控制器,只有一个注解@Mapping(value, method, produces),会自动通过不同的返回值做不同的处理,默认只需要设定value值即可,method默认为MethodType.HTTP,即接收所有的HTTP方法请求。
校验注解
| 注解 | 作用范围 | 说明 |
|---|---|---|
| @Date | 参数 | 校验注解的参数值为日期格式 |
| @DecimalMax(value) | 参数 | 校验注解的参数值小于等于@DecimalMax指定的value值 |
| @DecimalMin(value) | 参数 | 校验注解的参数值大于等于@DecimalMin指定的value值 |
| 参数 | 校验注解的参数值为电子邮箱格式 | |
| @Length(min, max) | 参数 | 校验注解的参数值长度在min和max区间内 |
| @Max(value) | 参数 | 校验注解的参数值小于等于@Max指定的value值 |
| @Min(value) | 参数 | 校验注解的参数值大于等于@Min指定的value值 |
| @NoRepeatSubmit | 控制器或动作 | 校验本次请求没有重复 |
| @NotBlank | 动作或参数 | 校验注解的参数值不是空白 |
| @NotEmpty | 动作或参数 | 校验注解的参数值不是空 |
| @NotNull | 动作或参数 | 校验注解的参数值不是null |
| @NotZero | 动作或参数 | 校验注解的参数值不是0 |
| @Null | 动作或参数 | 校验注解的参数值是null |
| @Numeric | 动作或参数 | 校验注解的参数值为数字格式 |
| @Pattern(value) | 参数 | 校验注解的参数值与指定的正则表达式匹配 |
| @Whitelist | 控制器或动作 | 校验本次请求在白名单范围内 |
原理
MVC
作为对比,先回顾一下,Spring MVC基于Servlet、DispatchServlet,核心流程:

解读:Tomcat的性能是足够的,但Spring Web处理太完备,以至于一个简单HTTP请求链过长,其中可能多做50%无意义操作。
Solon HTTP流程的核心流程处理:

Solon的处理很原生,主要在最底层的框架上面做一些必要的封装。简单请求里面,从SmartHttp透传请求,到业务方接收到请求,整体处理栈差不多在10层左右。
默认核心依赖solon-boot-smarthttp,HTTP层面还支持:jdkhttp,jetty、undertow。
| 框架 | 实现原理 | 主要特性 | 性能指标(线程模型&吞吐) | 适用场景 |
|---|---|---|---|---|
| SmartHttp(SmartBoot) | 基于Java NIO异步非阻塞,事件驱动,利用Epoll/kqueue | - 纯异步NIO架构 - 轻量高性能 - 灵活的协议扩展 - 支持全链路异步处理 | 高效纯异步线程模型,支持大量并发连接,低延迟,高吞吐(百万级TPS,视环境不同) | 高并发微服务、游戏、实时通信 |
| JDK HttpServer | Java自带,基于线程池的阻塞IO实现,简单HTTP服务器 | - 内置JDK,无需额外依赖 - 简单易用 - 仅支持基础HTTP功能 | 线程池阻塞模型,低并发适用,吞吐和延迟一般,不适合高并发 | 简单应用、快速开发、测试调试 |
| Jetty | 基于Java NIO异步非阻塞,Servlet容器,多线程队列 | - 完整Servlet规范支持 - 轻量灵活 - 支持HTTP/2,WebSocket - 丰富扩展和生态整合 | 异步线程池+请求队列,线程复用良好,性能优异,百万级TPS(硬件及配置相关) | 传统中大型 Web应用,Servlet生态 |
| Undertow | 基于Java NIO,借助XNIO框架实现轻量异步非阻塞 | - 极简轻量 - 支持Servlet 3.1异步API - HTTP/2支持 - 内置WebSocket | 高效事件驱动异步,线程数少,减少上下文切换,吞吐量高,性能与Jetty相似或略优 | 微服务、轻量Web服务及嵌入式服务器 |
容器启动
Spring容器启动也是一个超长的流程:

Solon启动是从Solon.class的start方法开始,SolonApp中主要可以分为3步:
- S1:创建SolonApp对象,用于加载容器等信息
- S2:
SolonApp.init(initialize)进行内部的初始化,主要是配置。配置就像Spring里面自动装配的内容,类似于spring-mybatis-starter这样,用来导入插件。如Solon里面就是mybatis-sqlhelper-solon-plugin - S3:
SolonApp.run加载插件和Bean
插件扫描处理:
java
protected void pluginScan(List<ClassLoader> classLoaders) {
for (ClassLoader classLoader : classLoaders) {
// 扫描配置
PluginUtil.scanPlugins(classLoader, pluginExcludeds, plugins::add);
}
// 扫描主配置
PluginUtil.findPlugins(AppClassLoader.global(), this, pluginExcludeds, plugins::add);
// 插件排序
Collections.sort(plugins);
}
Run方法中对Bean的扫描起点
java
//2.1.通过注解导入Bean(一般是些配置器)
beanImportTry();
//2.2.通过源扫描Bean
if (source() != null && enableScanning()) {
context().beanScan(source());
}
IoC
Spring IoC,网络上已经有很多资料。
Solon对Bean的管理大幅简化,Bean扫描起点在于AppContext.beanScan。

AOP
先看看,回顾一下Spring AOP:

面试必问知识点,你真的熟悉所有环节和步骤吗?反正我是一知半解。图抄自网络。
Solon对AOP直接简化为两个注解,使用上反而会复杂点:
- @Addition:局部对Context进行过滤,基于Filter进行代理;更多是前置或后置逻辑,无法通过它来控制目标方法的执行和修改返回值,用于快速加挂额外操作(Addition)
- @Around:局部对Bean进行拦截,基于MethodInterceptor,以在执行前后插入逻辑,还可以决定是否执行目标方法、修改返回值或参数
Solon相当于省略整个AOP的自动化处理,更接近于对象代理,所以配置起来会更复杂点:
java
// S1:准备一个注解
@Target({ElementType.METHOD, ElementType.TYPE}) //支持加在类或方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface AopDemo {
}
// S2:准备拦截器
@Slf4j
public class LogInterceptor implements Interceptor {
@Override
public Object doIntercept(Invocation inv) throws Throwable {
System.out.println("拦截器执行了");
return inv.invoke();
}
}
// S3 : 启动类里面注入
public static void main(String[] args) {
Solon.start(App.class, args, app->{
app.context().beanInterceptorAdd(AopDemo.class, new LogInterceptor());
});
}
源码分为两个部分:
- S1:创建和注入Bean时,提供BeanInvocationHandler代理对象
- S2:外部调用AOP方法时,首先调用的是代理对象,再由代理对象调用到方法里面
java
// S1 : 创建代理对象
// C- AppContext
if (tryProxy) {
// 是否需要自动代理
enableProxy = enableProxy || beanInterceptorHas(bw.clz());
if (enableProxy) {
ProxyBinder.global().binding(bw);
}
}
// S2 : 调用代理的方法
C- BeanInvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否存在自定义处理器,如果没有则调用默认的执行流程
if (this.handler == null) {
// 允许访问私有方法
method.setAccessible(true);
// 通过上下文获取对应类的对应方法的 MethodWrap(或类似封装)
// bw.context() 表示当前的上下文环境
// bw.rawClz() 获取原始类(目标类)
// methodGet 方法根据类和方法反射信息获取相应的包装MethodWrap对象
// invokeByAspect 表示通过AOP切面逻辑来执行这个方法,传入 this.bean 作为目标实例,args 作为参数
Object result = this.bw.context()
.methodGet(this.bw.rawClz(), method)
.invokeByAspect(this.bean, args);
return result;
}
}
实战
Maven项目引入依赖:
xml
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>4.1.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<!-- 打包插件 -->
<groupId>org.noear</groupId>
<artifactId>solon-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
启动类:
java
import org.noear.solon.Solon;
@Controller
public class App {
public static void main(String[] args) {
Solon.start(App.class, args);
}
@Mapping("/")
public String hello() {
return "Hello world!";
}
}
配置文件简化命名app.properties或app.yml,
和Spring相同的地方就略去。
java
// 手动注入Bean
Aop.wrapAndPut(UserDao.class);