不妨试试更快更小更灵活Java开发框架Solon
@
概述
定义
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的更多相关文章
- Nvidia发布更快、功耗更低的新一代图形加速卡
导读 不出意外的,Nvidia在其举行的Supercomputing 19大会上公布了很多新闻,这些我们将稍后提到.但被忽略的一条或许是其中最有趣的:一张更快.功耗更低的新一代图形加速卡. 多名与会者 ...
- 三表联查,这是我目前写过的最长的sql语句,嗯嗯,果然遇到问题才能让我更快成长,更复杂的语句也有了一些心得了
select sum(amount),sum(card_number) from sy_user inner join sy_admin on sy_user.customer_id=sy_admin ...
- 更快学习 JavaScript 的 6 个思维技巧
更快学习 JavaScript 的 6 个思维技巧 我们在学习JavaScript,或其他任何编码技能的时候,往往是因为这些拦路虎而裹足不前: 有些概念可能会造成混淆,尤其当你是从其他语言转过来的时候 ...
- C# String.Join 与 StringBuilder 对比,谁更快
String.Join 文档 StringBuilder 文档 这两天刷 Leedcode 做到一道 String 的题时突然想到这俩对比的问题,于是查了一下资料并简单对比了一下. 首先对于 ...
- 新型序列化类库MessagePack,比JSON更快、更小的格式
MessagePack is an efficient binary serialization format. It lets you exchange data among multiple la ...
- Gradle更小、更快构建APP的奇淫技巧
本文已获得原作者授权同意,翻译以及转载原文链接:Build your Android app Faster and Smaller than ever作者:Jirawatee译文链接:Gradle更小 ...
- vue3.0和2.0的区别,Vue-cli3.0于 8月11日正式发布,更快、更小、更易维护、更易于原生、让开发者更轻松
vue3.0和2.0的区别Vue-cli3.0于 8月11日正式发布,看了下评论,兼容性不是很好,命令有不少变化,不是特别的乐观vue3.0 的发布与 vue2.0 相比,优势主要体现在:更快.更小. ...
- TableCache设置过小造成MyISAM频繁损坏 与 把table_cache适当调小mysql能更快地工作
来源: 前些天说了一下如何修复损坏的MyISAM表,可惜只会修复并不能脱离被动的境地,只有查明了故障原因才会一劳永逸. 如果数据库服务非正常关闭(比如说进程被杀,服务器断电等等),并且此时恰好正在更新 ...
- Google 开源的依赖注入库,比 Spring 更小更快!
Google开源的一个依赖注入类库Guice,相比于Spring IoC来说更小更快.Elasticsearch大量使用了Guice,本文简单的介绍下Guice的基本概念和使用方式. 学习目标 概述: ...
随机推荐
- 【转载】一封面向社会,关于对近日来 CCF 不当行为之抗议的公开信
原文链接:https://101001011.github.io/2022/06/11/zhi-ccf-de-yi-feng-gong-kai-xin/ 原文作者:CCA(CCA's Blog) 前天 ...
- 使用three.js(webgl)搭建智慧楼宇、设备检测、数字孪生——第十三课
老子云:有道无术,术尚可求,有术无道,止于术. 咱开篇引用老子的话术,也没其它意思,只是最近学习中忽有感悟,索性就写了上来. 这句话用现代辩证思维理解,这里的"道" 大抵是指方法论 ...
- Python小游戏——外星人入侵(保姆级教程)第一章 03设置飞船图片 04创建Ship类
系列文章目录 第一章:武装飞船 03:设置飞船图片 04:创建Ship类--管理飞船行为的类 一.设置飞船图片 1.注意事项 A.将图片设置为位图bmp格式最简单,因为pygame默认加载位图 B.飞 ...
- ARC120D Bracket Score 2 (模拟)
题面 给一个长度为 2 N 2N 2N 的序列 A A A,定义一个长度为 2 N 2N 2N 的合法括号序列的 得分(score) 为: 对于每对配对的括号 i , j i,j i,j, ∣ A i ...
- 必应每日壁纸API
必应官网每天会更新不同的高质量背景图 我们可以通过 F12 开发者工具手动下载当天的壁纸,网上也有很多网站提供必应壁纸下载.如果我们想每天应用最新的壁纸到我们的网站上就需要手动下载再设置壁纸,比较麻烦 ...
- AI听曲识歌!哼曲、口哨吹,都能秒识! ⛵
作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 自然语言处理实战系列:https://www.showmeai.tech ...
- 一次较波折的MySQL调优
春节长假某日,阳光明媚,春暖花开,恰逢冬奥会开幕,想着一定是一个黄道吉日,必能顺风顺水.没想到却遇到一个有点小波折 的客户报障. 01故障起因 故障起因是客户前一天从自建MySQL迁移到云上RDS,在 ...
- VS Code 之KoroFileHeader插件
设置 在vscode左下角点击设置按钮,选择"设置",然后输入"fileheader", 文件头部注释:Fileheader:custom Made 函数注释: ...
- Docker日常工作常用命令
容器生命周期管理 Docker创建新容器并运行[run] 语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] OPTIONS说明: -a stdin: 指 ...
- ClickHouse(05)ClickHouse数据类型详解
ClickHouse属于分析型数据库,ClickHouse提供了许多数据类型,它们可以划分为基础类型.复合类型和特殊类型.其中基础类型使ClickHouse具备了描述数据的基本能力,而另外两种类型则使 ...