@

概述

定义

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. 议题征集令 | Apache DolphinScheduler Meetup 2021 来啦,议题征集正式开启!

    点击上方 蓝字关注我们 社区的小伙伴们,经过精心筹备,我们很高兴地宣布,Apache DolphinScheduler Meetup 2021 将于 2021 年 11 月 27 日到来! 在 Mee ...

  2. 浅淡 Apache Kylin 与 ClickHouse 的对比

    作者简介 周耀,Kyligence 解决方案架构师,Apache Kylin.Apache Superset Contributor. Apache Kylin 和 ClickHouse 都是目前市场 ...

  3. java学习第一天.day06

    方法 方法的优点 1. 使程序变得更简短而清晰. 2. 有利于程序维护. 3. 可以提高程序开发的效率. 4. 提高了代码的重用性. static的作用 static在方法中如果没有添加就只能用对象调 ...

  4. RabbitMQ 入门系列:9、扩展内容:死信队列:真不适合当延时队列。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  5. Java基础——01

    今日学习 2020-2-27 Java多态 多态性格式 /* 代码中体现多态性 其实就是一句话:父类指向子类对象 格式: 父类名称 对象名= new 子类名称(): 或者 接口名称 对象名 = new ...

  6. C#/.NET/.NET Core优秀项目框架推荐

    前言: 为.NET开源者提供的一个推荐自己优秀框架的地址,大家可以把自己的一些优秀的框架,或者项目链接地址存到在这里,提供给广大.NET开发者们学习(排名不分先后). Github项目仓库收集地址:h ...

  7. 一文学会Spring JDBC 使用

    Spring JDBC 1.JDBC JDBC 就是 数据库开发 操作的 代名词,因为只要是现代商业项目的开发那么一定是离不开 数据库 的,不管你搞的是什么,只要是想使用动态的开发结构,那么一定就是 ...

  8. [Python]-opencv-python模块(cv2)-图片读取和格式转换

    python常常用opencv模块来处理图像. import cv2 as cv 读取图片:imread() 默认按照彩色三通道读取: img = cv2.imread(path) 读取灰度图: im ...

  9. Kubernetes 监控--Alertmanager

    前面我们学习 Prometheus 的时候了解到 Prometheus 包含一个报警模块,就是我们的 AlertManager,Alertmanager 主要用于接收 Prometheus 发送的告警 ...

  10. 清除已安装的rook-ceph集群

    官方文档地址:https://rook.io/docs/rook/v1.8/ceph-teardown.html 如果要拆除群集并启动新群集,请注意需要清理的以下资源: rook-ceph names ...