# tiny
**Repository Path**: weishixiang/tiny
## Basic Information
- **Project Name**: tiny
- **Description**: 小巧的java应用微内核通用框架, 可用于构建小工具项目,web项目,各种大大小小的项目
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 15
- **Created**: 2022-08-13
- **Last Updated**: 2022-08-13
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 介绍
小巧的java应用微内核框架. 基于 [enet](https://gitee.com/xnat/enet) 事件环型框架结构
目前大部分高级语言都解决了编程内存自动管理的问题(垃圾回收), 但并没有解决cpu资源自动管理的问题。
基本上都是程序员主动创建线程或线程池,这些线程是否被充分利用了,在应用不同的地方创建是否有必要,
太多的线程是否造成竞争性能损耗。毕竟线程再多,而决定并发的是cpu的个数。
所以需要框架来实现一个智能执行器(线程池):根据应用的忙碌程度自动创建和销毁线程,
即线程池会自己根据排对的任务数和当前池中的线程数的比例判断是否需要新创建线程(和默认线程池的行为不同)。
会catch所有异常, 不会被业务异常给弄死(永动机)。
程序只需通过配置最大最小资源自动适配, 类似现在的数据库连接池。这样既能充分利用线程资源,
也不会造成线程的空转,减小线程过多调度的性能浪费。
> 所以系统性能只由线程池大小属性 sys.exec.corePoolSize=8, sys.exec.maximumPoolSize=16 和 jvm内存参数 -Xmx1024m 控制
框架设计一种轻量级执行器(伪协程): __Devourer__ 来控制执行模式(并发,暂停/恢复,速度等)
上层服务应该只关注怎么组装执行任务,然后提交给 __Devourer__ 或直接给执行线程池。如下图:

# 安装教程
```xml
cn.xnatural
tiny
1.1.6
```
# 初始化
```java
// 创建一个应用
final AppContext app = new AppContext();
// 添加服务 server1
app.addSource(new ServerTpl("server1") {
@EL(name = "sys.starting")
void start() {
log.info("{} start", name);
}
});
// 添加自定义服务
app.addSource(new TestService());
// 应用启动(会依次触发系统事件)
app.start();
```
> 基于事件环型微内核框架结构图
>
> > 以AppContext#EP为事件中心的挂载服务结构

## 系统事件: app.start() 后会依次触发 sys.inited, sys.starting, sys.started
+ sys.inited: 应用始化完成(环境配置, 系统线程池, 事件中心)
+ sys.starting: 通知所有服务启动. 一般为ServerTpl
+ sys.started: 应用启动完成
+ sys.stopping: 应用停止事件(kill pid)
## 配置
> 配置文件加载顺序(优先级从低到高):
* classpath: app.properties, classpath: app-[profile].properties
* file: ./app.properties, file: ./app-[profile].properties
* configdir: app.properties, configdir: app-[profile].properties
* 自定义环境属性配置(重写方法): AppContext#customEnv
* System.getProperties()
>+ 系统属性(-Dconfigname): configname 指定配置文件名. 默认: app
>+ 系统属性(-Dprofile): profile 指定启用特定的配置
>+ 系统属性(-Dconfigdir): configdir 指定额外配置文件目录
* 只读取properties文件. 按顺序读取app.properties, app-[profile].properties 两个配置文件
* 配置文件支持简单的 ${} 属性替换
## 添加 [xhttp](https://gitee.com/xnat/xhttp) 服务
```properties
### app.properties
web.hp=:8080
```
```java
app.addSource(new ServerTpl("web") { //添加web服务
HttpServer server;
@EL(name = "sys.starting", async = true)
void start() {
server = new HttpServer(attrs(), exec());
server.buildChain(chain -> {
chain.get("get", hCtx -> {
hCtx.render("xxxxxxxxxxxx");
});
}).start();
}
@EL(name = "sys.stopping")
void stop() {
if (server != null) server.stop();
}
});
```
## 添加 [jpa](https://gitee.com/xnat/jpa) 数据库操作服务
```properties
### app.properties
jpa_local.url=jdbc:mysql://localhost:3306/test?useSSL=false&user=root&password=root&allowPublicKeyRetrieval=true
```
```java
app.addSource(new ServerTpl("jpa_local") { //数据库 jpa_local
Repo repo;
@EL(name = "sys.starting", async = true)
void start() {
repo = new Repo(attrs()).init();
exposeBean(repo); // 把repo暴露给全局, 即可以通过@Inject注入
ep.fire(name + ".started");
}
@EL(name = "sys.stopping", async = true, order = 2f)
void stop() { if (repo != null) repo.close(); }
});
```
## 添加 [sched](https://gitee.com/xnat/jpa) 时间调度服务
```java
app.addSource(new ServerTpl("sched") {
Sched sched;
@EL(name = "sys.starting", async = true)
void start() {
sched = new Sched(attrs(), exec()).init();
exposeBean(sched);
ep.fire(name + ".started");
}
@EL(name = "sched.after")
void after(Duration duration, Runnable fn) {sched.after(duration, fn);}
@EL(name = "sys.stopping", async = true)
void stop() { if (sched != null) sched.stop(); }
});
```
## 动态按需添加服务
```java
@EL(name = "sys.inited")
void sysInited() {
if (!app.attrs("redis").isEmpty()) { //根据配置是否有redis,创建redis客户端工具
app.addSource(new RedisClient())
}
}
```
## 让系统心跳(即:让系统安一定频率触发事件 sys.heartbeat)
> 需要用 [sched](https://gitee.com/xnat/sched) 添加 _sched.after_ 事件监听
```java
@EL(name = "sched.after")
void after(Duration duration, Runnable fn) {sched.after(duration, fn);}
```
> 每隔一段时间触发一次心跳, 1~4分钟(两个配置相加)随机心跳
> + 配置(sys.heartbeat.minInterval) 控制心跳最小时间间隔
> + 配置(sys.heartbeat.randomInterval) 控制心跳最大时间间隔
```java
// 心跳事件监听器
@EL(name = "sys.heartbeat", async = true)
void myHeart() {
System.out.println("咚");
}
```
## 服务基础类: ServerTpl
> 推荐所有被加入到AppContext中的服务都是ServerTpl的子类
```properties
### app.properties
服务名.prop=1
```
```java
app.addSource(new ServerTpl("服务名") {
@EL(name = "sys.starting", async = true)
void start() {
// 初始化服务
}
})
```
### bean注入 @Inject(name = "beanName")
> 注入匹配规则: (已经存在值则不需要再注入)
> > 1. 如果 @Inject name 没配置
> > > 先按 字段类型 和 字段名 匹配, 如无匹配 再按 字段类型 匹配
> > 2. 则按 字段类型 和 @Inject(name = "beanName") beanName 匹配
```java
app.addSource(new ServerTpl() {
@Inject Repo repo; //自动注入
@EL(name = "sys.started", async = true)
void init() {
List