@

概述

定义

Solon 官网地址 https://solon.noear.org/

Solon GitHub源码地址 https://github.com/noear/solon

Solon for java,一个更现代感的,轻量级应用开发框架,崇尚克制、简洁、开放、生态设计理念。最新版本为1.10.7

Solon从项目启动以来,参考过大量前人的作品。尤其是 Spring Boot、jFinal、Javalin 和 Asp.Net,吸取了诸多优点,且避开很多繁重的设计。历时多年,内核始终保持 0.1Mb 的身材,超高的跑分,良好而自由的使用体验。

目前支持jdk8、jdk11、jdk17、jdk19四个大版本,开发定制方便,可通过组合不同的插件快速开发不同的需求,开发人员几乎可使用与SpringBoot相似的开发方式。其Solon Cloud 为一系列分布式开发的接口标准和配置规范,相当于DDD模式里的防腐层概念,是 Solon 的微服务架构模式开发解决方案。在开发使用上官方也提供其与SpringBoot、SpringCloud、Dubbo的详细区别,使用时查阅官方文档即可。

性能

Solon 根据官方提供数据,比传统的Java应用特别是Spring生态开发的应用启动快 5 ~ 10 倍,qps 高 2~ 3 倍,运行时内存节省 1/3 ~ 1/2,打包可以缩到 1/2 ~ 1/10。因此成为更现代感的应用开发框架,实现更快、更小、更少、更自由!

  • 快:Qps 可达10万之多
  • 小:内核 0.1Mb,最小 Web 完整开发单位 1Mb(相比Springboot项目包,小到可以乎略不计了)
  • 自由:代码操控自由,除了注解模式之外,还可以按需手动;框架选择自由:可以用 solon-web 这样的快速开发集成包。也可以按项目需要选择不同的插件组装,比如:为非Solon项目添加solon.boot.jlhttp,0.2Mb 即可让项目实现 http+mvc 支持。

架构

  • 缘起统一的处理架构想法(俗称:三源合一):Http、Socket、WebSocket。不同的通讯信号,进行统一架构处理,且小巧。 对于 Socket 和 WebSocket,在原 消息+监听 的模式之外增加了 上下文+处理 模式

  • 关于应用内在的启动过程(即:应用的生命周期):串行的处理过程(含四个事件扩展点 + 两个函数扩展点)

  • 请求的处理过程

  • Ioc & Aop 内部结构

  • 现有家簇成员图谱

实战

Solon Web示例

下载官方的helloworld示例 体验下Solon 轻量和快。此外还可以下载官网提供丰富的配套示例:

项目 地址 说明
solon-examples https://gitee.com/noear/solon-examples 配套"学习/科目学习"进行演示

下载完解压后导入Idea中,是个标准的maven项目,pom文件引入solon的父依赖和核心依赖

<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
</dependency>

一个配置文件app.yml,一个启动类DemoApp,是不是和SpringBoot很相似,Solon 是一个容器型的应用开发框,在main方法中使用Solon.start启动。app.yml内容如下:

server.port: 8080
solon.app:
name: demoapp
group: demo

这里简单修改hello方法的返回结果如下,可以直接运行,也可以先通过mvn clean package -DskipTests打包后再使用java -jar demo.jar运行。

几小行代码一个http接口就完成,启动速度非常快只用3ms,访问http://localhost:8080/hello?name=itxiaoshen 返回正确的结果

Solon Mybatis-Plus示例

环境准备:创建MySQL数据库test、表appx,并插入测试数据

CREATE TABLE `appx` (
`app_id` INT NOT NULL AUTO_INCREMENT COMMENT '应用ID',
`app_key` VARCHAR(40) DEFAULT NULL COMMENT '应用访问KEY',
`akey` VARCHAR(40) DEFAULT NULL COMMENT '(用于取代app id 形成的唯一key) //一般用于推广注册之类',
`ugroup_id` INT DEFAULT '0' COMMENT '加入的用户组ID',
`agroup_id` INT DEFAULT NULL COMMENT '加入的应用组ID',
`name` VARCHAR(50) DEFAULT NULL COMMENT '应用名称',
`note` VARCHAR(50) DEFAULT NULL COMMENT '应用备注',
`ar_is_setting` INT NOT NULL DEFAULT '0' COMMENT '是否开放设置',
`ar_is_examine` INT NOT NULL DEFAULT '0' COMMENT '是否审核中(0: 没审核 ;1:审核中)',
`ar_examine_ver` INT NOT NULL DEFAULT '0' COMMENT '审核 中的版本号',
`log_fulltime` DATETIME DEFAULT NULL,
PRIMARY KEY (`app_id`),
UNIQUE KEY `IX_akey` (`akey`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='应用表'; INSERT appx(app_key,akey,ugroup_id,agroup_id,NAME,note,ar_is_setting,ar_is_examine,ar_examine_ver,log_fulltime)
VALUES('asdfghjk','aaaaabbbbb',100,1001,'抖音','时尚短视频',0,1,1,NOW());
INSERT appx(app_key,akey,ugroup_id,agroup_id,NAME,note,ar_is_setting,ar_is_examine,ar_examine_ver,log_fulltime)
VALUES('sdfsdf','ccccdddd',102,1002,'招行','储蓄',0,1,1,NOW());
INSERT appx(app_key,akey,ugroup_id,agroup_id,NAME,note,ar_is_setting,ar_is_examine,ar_examine_ver,log_fulltime)
VALUES('34543','eeeegggg',103,1003,'有道词典','翻译',0,1,1,NOW());

添加mybatis-plus和mysql相关依赖如下:

        <dependency>
<groupId>org.noear</groupId>
<artifactId>mybatis-plus-extension-solon-plugin</artifactId>
</dependency> <dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>

app.yml文件增加数据源和mybatis-plus的配置

test.db1:
schema: rock
jdbcUrl: jdbc:mysql://192.168.40.100:3308/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: 123456 ##默认
mybatis.db1:
typeAliases: #支持包名 或 类名(.class 结尾)
- "demo4031.model"
mappers: #支持包名 或 类名(.class 结尾)或 xml(.xml结尾 或 *.xml 结尾)
- "demo4031.dso.mapper"
# - "demo4031/dso/*.xml"
configuration:
cacheEnabled: false
mapUnderscoreToCamelCase: true
logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
globalConfig:
banner: false
metaObjectHandler: "demo4031.dso.MetaObjectHandlerImpl"
dbConfig:
logicDeleteField: "deleted"
logicDeleteValue: "2"

mapper接口和mapper.xml文件与Spring整合Mybatis基本相同

@Mapper
public interface AppxMapper {
AppxModel appx_get();
Page<AppxModel> appx_get_page(Page<AppxModel> page);
AppxModel appx_get2(int app_id);
void appx_add();
Integer appx_add2(int v1); @Select("SELECT * FROM INFORMATION_SCHEMA.TABLES")
List<DbTable> listTables();
}

再添加业务的Service和实现类,最后添加PlusController控制器实现

@Mapping("/plus/")
@Controller
public class PlusController {
@Inject
AppServicePlus appServicePlus; @Mapping("test")
public AppxModel test() {
return appServicePlus.getById(2);
}
}

添加mybatis-plus分页的PageController控制器实现

@Mapping("/page/")
@Controller
public class PageController {
@Db
AppxMapper appxMapper; @Mapping("test")
public Object test() throws Throwable {
Page<AppxModel> page = new Page<>(2, 2);
return appxMapper.appx_get_page(page);
}
}

启动程序后日志输出如下

访问http://localhost:8080/plus/test,返回正确的结果

访问http://localhost:8080/page/test ,返回正确的分页结果

Solon WebSocket示例

引入依赖

        <dependency>
<groupId>org.noear</groupId>
<artifactId>nami</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon.socketd.client.websocket</artifactId>
</dependency>

简单几行代码就实现WebSocket的服务端编程

@ServerEndpoint(value = "/ws/demo/{id}")
public class WebSocket implements Listener {
@Override
public void onOpen(Session session) {
//path var
String id = session.param("id");
//query var
String token = session.param("token");
/*此处可以做签权;会话的二次组织等...*/
} @Override
public void onMessage(Session session, Message message) throws IOException {
//message.setHandled(true); //设为true,则不进入mvc路由
session.send("你发了:" + message.bodyAsString());
}
}

然后通过一个debug.htm通过javascript实现WebSocket收发功能,App启动类开启enableWebSocket

public class App {
public static void main(String[] args) {
//
// 启动Solon,并开启WebSocket监听;同时添加/路径跳转
//
Solon.start(App.class, args, app -> app.enableWebSocket(true)).get("/", c -> {
c.redirect("/debug.htm");
});
}
}

启动App后日志输出如下

访问http://localhost:8080/ 输入发送信息后服务端打印收到的输入信息

Solon Remoting RPC示例

RPC的实现分为3个模块,RPC提供者的实现、公共模块、服务消费者,公共模块存放数据模型和接口,可以同时提供给提供者和消费者引用。

服务提供者添加solon-rpc依赖

        <dependency>
<groupId>org.noear</groupId>
<artifactId>solon-rpc</artifactId>
</dependency>

服务提供者通过@Remoting注解实现RPC服务,代码如下

@Mapping("/user/")
@Remoting
public class UserServiceImpl implements UserService {
@Override
public UserModel getUser(Integer userId) {
UserModel model = new UserModel();
model.setId(userId);
model.setName("user-" + userId);
return model;
}
}

服务消费者添加如下依赖

        <dependency>
<groupId>org.noear</groupId>
<artifactId>solon-rpc</artifactId>
</dependency> <dependency>
<groupId>org.noear</groupId>
<artifactId>solon.cloud</artifactId>
</dependency>

app.yml配置文件配置服务发现的地址,也即是服务提供者提供的地址

server.port: 8080

solon.app:
name: demoapp
group: demo solon.cloud.local:
discovery:
service:
local:
- "http://localhost:8081"

通过@NamiClient注解实现RPC远程方法的调用

@Controller
public class UserController {
//使用负载
@NamiClient(name = "local",path = "/user/")
UserService userService; @Mapping("test")
public UserModel test() {
UserModel user = userService.getUser(100);
System.out.println(user);
return user;
}
}

启动服务提供者和服务消费者

访问服务消费者测试Controller的测试接口,http://localhost:8080/test ,返回正确结果

Solon Cloud Nacos示例

引入依赖

        <dependency>
<groupId>org.noear</groupId>
<artifactId>nacos-solon-cloud-plugin</artifactId>
</dependency>

先准备好Nacos Server,这里就直接使用前面文章已部署好的Nacos,创建好nacos的test命名空间,为了演示读取nacos的配置,在test下创建一个组为demo的test.properties,并添加db1.url的键值对。

然后在服务注册端的本地app.yml配置文件添加相关nacos的配置信息

server.port: 7112
solon.app:
namespace: test
group: demo
name: helloapi #发现服务使用的应用名(在Demo,将被NimaClient引用)
solon.cloud.nacos:
server: 192.168.50.95:8848 #nacos服务地址
username: nacos #nacos链接账号
password: nacos #nacos链接密码

声明HelloService接口,服务注册方实现接口,服务端的工作就完成了

@Mapping("/rpc/")@Remotingpublic class HelloServiceRemoteImp implements HelloService {    @Override    public String hello() {        return "remote: hello";    }}

作为服务发现的客户端本地app.yml配置文件添加相关nacos的配置信息如下

solon.app:  namespace: test  group: demo       #配置服务使用的默认组  name: helloapp    #发现服务使用的应用名solon.cloud.nacos:  server: 192.168.50.95:8848   #nacos服务地址  username: nacos             #nacos链接账号  password: nacos             #nacos链接密码  config:    load: "test.properties"

测试的客户端中也是通过注解@NamiClient注入HelloService接口,添加一个测试controller控制器演示

@Controllerpublic class TestController {    //这是远程的    @NamiClient    HelloService helloService;    @Mapping("/test")    public String test() throws Exception {        helloService.hello();        String temp = helloService.hello();        System.out.println("helloService return"+temp);        return temp + "," + Solon.cfg().get("db1.url");    }}

已启动服务注册serverApp和服务发现ClientApp

查看Nacos服务管理可以看下服务名已经正常注册了

访问测试地址http://localhost:8080/test,可以看到成功调用服务注册方的方法,也打印从Nacos配置中心的配置项值,至此,已经实现基于Nacos的配置、服务注册和发现的基本功能。

**本人博客网站 **IT小神 www.itxiaoshen.com

不妨试试更快更小更灵活Java开发框架Solon的更多相关文章

  1. Nvidia发布更快、功耗更低的新一代图形加速卡

    导读 不出意外的,Nvidia在其举行的Supercomputing 19大会上公布了很多新闻,这些我们将稍后提到.但被忽略的一条或许是其中最有趣的:一张更快.功耗更低的新一代图形加速卡. 多名与会者 ...

  2. 三表联查,这是我目前写过的最长的sql语句,嗯嗯,果然遇到问题才能让我更快成长,更复杂的语句也有了一些心得了

    select sum(amount),sum(card_number) from sy_user inner join sy_admin on sy_user.customer_id=sy_admin ...

  3. 更快学习 JavaScript 的 6 个思维技巧

    更快学习 JavaScript 的 6 个思维技巧 我们在学习JavaScript,或其他任何编码技能的时候,往往是因为这些拦路虎而裹足不前: 有些概念可能会造成混淆,尤其当你是从其他语言转过来的时候 ...

  4. C# String.Join 与 StringBuilder 对比,谁更快

    String.Join 文档      StringBuilder 文档 这两天刷 Leedcode 做到一道 String 的题时突然想到这俩对比的问题,于是查了一下资料并简单对比了一下. 首先对于 ...

  5. 新型序列化类库MessagePack,比JSON更快、更小的格式

    MessagePack is an efficient binary serialization format. It lets you exchange data among multiple la ...

  6. Gradle更小、更快构建APP的奇淫技巧

    本文已获得原作者授权同意,翻译以及转载原文链接:Build your Android app Faster and Smaller than ever作者:Jirawatee译文链接:Gradle更小 ...

  7. vue3.0和2.0的区别,Vue-cli3.0于 8月11日正式发布,更快、更小、更易维护、更易于原生、让开发者更轻松

    vue3.0和2.0的区别Vue-cli3.0于 8月11日正式发布,看了下评论,兼容性不是很好,命令有不少变化,不是特别的乐观vue3.0 的发布与 vue2.0 相比,优势主要体现在:更快.更小. ...

  8. TableCache设置过小造成MyISAM频繁损坏 与 把table_cache适当调小mysql能更快地工作

    来源: 前些天说了一下如何修复损坏的MyISAM表,可惜只会修复并不能脱离被动的境地,只有查明了故障原因才会一劳永逸. 如果数据库服务非正常关闭(比如说进程被杀,服务器断电等等),并且此时恰好正在更新 ...

  9. Google 开源的依赖注入库,比 Spring 更小更快!

    Google开源的一个依赖注入类库Guice,相比于Spring IoC来说更小更快.Elasticsearch大量使用了Guice,本文简单的介绍下Guice的基本概念和使用方式. 学习目标 概述: ...

随机推荐

  1. 技术分享 | 在MySQL对于批量更新操作的一种优化方式

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 作者:景云丽.卢浩.宋源栋 GreatSQL社区原创内容未经授权不得随意使用,转 ...

  2. 重构、插件化、性能提升 20 倍,Apache DolphinScheduler 2.0 alpha 发布亮点太多!

    点击上方 蓝字关注我们 社区的小伙伴们,好消息!经过 100 多位社区贡献者近 10 个月的共同努力,我们很高兴地宣布 Apache DolphinScheduler 2.0 alpha 发布.这是 ...

  3. 解决linux下U盘变成只读模式

    在最近的一个项目里,需要将linux下的些文件拷贝出来.插入U盘后,发现是只读模式. U盘可以写出,不能写入. 折腾了一翻: 最后这样解决的: 将U盘插入到windows下 执行 chkdsk g: ...

  4. 原生应用、Web 应用和混合应用的概念,以及 Flutter 技术是什么

    应用类型 原生应用 原生应用就是使用特定的语言开发的应用,例如 Android 原生应用.Windows 原生应用.iOS 原生应用等.开发 Android 原生应用时,其特定的编程语言为 Java ...

  5. 面试突击77:Spring 依赖注入有几种?各有什么优缺点?

    IoC 和 DI 是 Spring 中最重要的两个概念,其中 IoC(Inversion of Control)为控制反转的思想,而 DI(Dependency Injection)依赖注入为其(Io ...

  6. ARC120F Wine Thief (组合数学)

    题面 有一个长为 N N N 的序列,相邻的两个数中只能选一个,总共选 k k k 个数,一种方案的价值为选的 k k k 个数的和,问所有合法方案的价值总和,答案对 998244353 取模. 1 ...

  7. PHP为任意页面设访问密码

    使用方法 把下面的代码存为php文件,下面的整段代码是验证过程,然后在你入口页进行调用例如命名为MkEncrypt.php,那么在入口页进行       require_once('MkEncrypt ...

  8. 【java】学习路径39-Buffered缓冲输出流

    import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; pu ...

  9. .Net Core 配置文件读取 - IOptions、IOptionsMonitor、IOptionsSnapshot

    原文链接:https://www.cnblogs.com/ysmc/p/16637781.html 众所周知,appsetting.json 配置文件是.Net 的重大革新之心,抛开了以前繁杂的xml ...

  10. LIKE与等式查询比较

    我们知道 char 是定长类型的数据,如果数据长度小于定义的长度,会在字符串尾部加上空格.而对于空格的处理,对于等式匹配,或length等,会忽略空格.而对于like 或模式匹配,空格不能忽略. 一. ...