对比 Spring ,Solon 在实现上又有什么差异?
2025-04-22 08:01 阅读(26)

一. 前言

Solon 是 国产的 Java 企业级应用开发框架 ,算是国内在体系和生态上都比较全面的框架了。

这个框架在 内存占用 \ 启动速度上都很亮眼, 据官方数据 ,整体性能对比 Spring 提高了多倍。

这一篇就来感受一下这个框架 ,并且从源码的角度上 ,来感受一下这个框架的种种,对比一下 Spring ,它又优化了什么。

二. 基础使用


Maven 依赖

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

启动类

import org.noear.solon.Solon;
public class App {
    public static void main(String[] args) {
        Solon.start(App.class, args);
    }
}

Rest 接口

@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 HttpServerJava 自带,基于线程池的阻塞 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 的扫描处理 :


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 的扫描起点


//2.1.通过注解导入bean(一般是些配置器)
beanImportTry();

//2.2.通过源扫描bean
if (source() != null && enableScanning()) {
    context().beanScan(source());
}

Spring 对比 :

3.2 Bean 的管理 (= IOC)

Bean 真正扫描的起点在于 :AppContext # beanScan 部分 :

Spring部分 :

3.3 AOP 部分

这部分有点意思 ,Solon 对 AOP 进行了很直接的简化 ,简化为了两个注解 ,使用上反而会复杂点 :


@Addition : 局部对 Context 进行过滤 , 基于 Filter 进行代理


更多是 “前置” 或 “后置” 逻辑

无法通过它来控制目标方法的执行和修改返回值

用于快速加挂“额外操作(Addition) ”



@Around : 局部对 Bean 进行拦截 ,基于 MethodInterceptor


以在执行前后插入逻辑,还可以决定是否执行目标方法、修改返回值或参数




所以 ,其实 @Around 更像之前 Spring 的 AOP 流程。由于 Solon 相当于省略了整个 AOP 的自动化处理 ,更接近于对象代理 ,所以配置起来会更复杂点 :



// 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 方法时候 ,首先调用的是代理对象 ,再由代理对象调用到方法里面



// 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 , 很全面 ,但是也太难了、

https://www.zuocode.com

容器的处理 Solon 只有两个核心 : Plugin (组件) + Bean 加载



IOC 层面也简单很多 ,这里就不细说了 ,看过 Spring 源码的都能懂


没看过的推荐我自己的这个专栏 @ juejin.cn/column/6961…


作者:志字辈小蚂蚁

链接:https://juejin.cn