一. 前言
Solon 是 国产的 Java 企业级应用开发框架 ,算是国内在体系和生态上都比较全面的框架了。
这个框架在 内存占用 \ 启动速度上都很亮眼, 据官方数据 ,整体性能对比 Spring 提高了多倍。
这一篇就来感受一下这个框架 ,并且从源码的角度上 ,来感受一下这个框架的种种,对比一下 Spring ,它又优化了什么。
二. 基础使用
Maven 依赖
xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>3.2.0</version>
</parent>
<groupId>org.example</groupId>
<artifactId>solonSimpleDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>solonSimpleDemo</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
</project>
启动类
java
import org.noear.solon.Solon;
public class App {
public static void main(String[] args) {
Solon.start(App.class, args);
}
}
Rest 接口
java
@Controller
public class HelloController {
/**
* 这是直接返回值
* */
@Mapping("/")
public String hello() {
return "Hello world!";
}
/**
* 这是返回个对象(以json形式)
* */
@Mapping("/json")
public Map hello_json() {
Map<String,Object> map = new HashMap<>(); //实体也ok
map.put("message", "Hello world!");
return map;
}
}
阶段总结 :
- 从最简单的使用层面 ,可以看到和Spring区别不大 ,或者说是沿用统一的规范
- 启动时间确实更快了 ,调用接口等功能也没有太大的问题
三. 深入原理
3.1 Rest 接口的使用
我们知道 ,Spring 的 MVC 功能是基于 Servlet
的 ,其根本的特性是通过 DispatchServlet
接收来自于外部的各种请求。
而 Solon 里面要简单很多 ,其默认核心的依赖是 solon-boot-smarthttp ,而从官方的依赖列表里面 ,Solon 的 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 服务及嵌入式服务器 |
solon HTTP 流程的核心流程处理 :

这是 Spring MVC 的核心流程 :

阶段总结 :
Spring 默认带的 Tomcat 有问题吗 ? 一点问题没有 , Tomcat 的性能是够的 , 这一点已经有大量案例了 。
但是从上面流程可以对比出来 ,Spring 的 Web 处理太完备了 ,以至于一个简单的 HTTP 请求链过长
,其中可能多做了50% 的无意义操作.
Solon 的处理很原生 ,主要在最底层的框架上面做了一些必要的封装。简单请求里面 ,从SmartHttp 透传请求 ,到业务方接收到请求 ,整体的处理栈差不多在10层左右。
3.2 容器的启动 ( = ApplicationContext)
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
Plugin 的扫描处理 :
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());
}
3.2 Bean 的管理 (= IOC)
Bean 真正扫描的起点在于 :AppContext # beanScan 部分 :

阶段总结 :
3.3 AOP 部分
这部分有点意思 ,Solon 对 AOP 进行了很直接的简化 ,简化为了两个注解 ,使用上反而会复杂点 :
- @Addition : 局部对 Context 进行过滤 , 基于 Filter 进行代理
- 更多是 "前置" 或 "后置" 逻辑
- 无法通过它来控制目标方法的执行和修改返回值
- 用于快速加挂"额外操作(Addition) "
- @Around : 局部对 Bean 进行拦截 ,基于 MethodInterceptor
- 以在执行前后插入逻辑,还可以决定是否执行目标方法、修改返回值或参数
所以 ,其实 @Around 更像之前 Spring 的 AOP 流程。由于 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;
}
}
Spring AOP 做了什么 ?

- 这是之前 Spring AOP 的主流程梳理 ,流程相对而言长了太多
总结
时间精力有限 ,整体代码没有太深入的看了。整体使用下来 ,如果项目比较小 ,资源也紧张 ,Solon 是一个很值得考虑的框架。
- 使用上 : 不适合改造旧项目 ,但是新项目使用没什么压力 ,文档丰富,使用不需要太大的难度
- 深度问题 : 由于对整个流程做了极大的简化 ,所以出问题基本上可以通过读源码解决
- 性能和内存占用现在看到的会有明显的提升 ,但是改造大的生产项目太难了 ,没办法进行比较
个人的一点思路 :
Spring 是全面可靠的 ,这点无容置疑 , 所以生产级的大项目 ,相信还是会以 Spring 为主流。
但是个人的一些小 Demo ,和一些资源更少的场景 ,就可以考虑使用 Solon了 ,不用自己造轮子 ,也不会浪费 Spring 的性能。
关于设计的思想 :
核心源码大致走了一遍 ,Solon 本身设计上是有一些明确的思路的 :
- AOP 更偏向于显示 的声明(没试过能不能通过包扫描的方式)
- 其实写了这么多年代码 ,
Spring AOP 的使用率并不高
,更多的是Spring自己在用 ,业务上用到也主要是日志级别的处理
- 其实写了这么多年代码 ,
- Spring 的容器确实过于复杂了 ,各种
Listener
,Aware
,PostProcessor
, 很全面 ,但是也太难了、- 容器的处理 Solon 只有两个核心 :
Plugin (组件) + Bean 加载
- 容器的处理 Solon 只有两个核心 :
- IOC 层面也简单很多 ,这里就不细说了 ,看过 Spring 源码的都能懂
- 没看过的推荐我自己的这个专栏 @ juejin.cn/column/6961...
最后的最后 ❤️❤️❤️👇👇👇
- 👈 欢迎关注 ,超200篇优质文章,未来持续高质量输出 🎉🎉
- 🔥🔥🔥 系列文章集合,高并发,源码应有尽有 👍👍
- 走过路过不要错过 ,知识无价还不收钱 ❗❗