Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/swingfrog/summer

这是一个轻量级的、一站式的java游戏服务器框架,也可用于开发简单的web服务。基于netty实现了高性能通讯,支持tcp、http、websocket等协议,支持protobuf、json两种数据格式,支持以配置的形式轻松开启多端口网络服务。支持RPC远程调用,支持以优雅的方式实现远程调用,支持调用超时重试、幂等调用。封装了持久化层,提供数据访问和数据落地接口,支持异步新增、保存、删除数据,支持主键或指定其他字段进行数据缓存。支持简单的ioc,业务层使用依赖注入实现逻辑。封装了伪协程实现方案Promise,可用于解决地狱式回调等问题。支持MVC、领域、ECS架构。
https://github.com/swingfrog/summer

aop dao distributed druid game ioc ioc-container java mmo mmorpg-server mvc netty orm protobuf quartz redis rpg server server-framework summer

Last synced: 1 day ago
JSON representation

这是一个轻量级的、一站式的java游戏服务器框架,也可用于开发简单的web服务。基于netty实现了高性能通讯,支持tcp、http、websocket等协议,支持protobuf、json两种数据格式,支持以配置的形式轻松开启多端口网络服务。支持RPC远程调用,支持以优雅的方式实现远程调用,支持调用超时重试、幂等调用。封装了持久化层,提供数据访问和数据落地接口,支持异步新增、保存、删除数据,支持主键或指定其他字段进行数据缓存。支持简单的ioc,业务层使用依赖注入实现逻辑。封装了伪协程实现方案Promise,可用于解决地狱式回调等问题。支持MVC、领域、ECS架构。

Awesome Lists containing this project

README

        

# Summer
- 这是一个轻量级的、一站式的java游戏服务器框架,也可用于开发简单的web服务。
- 基于netty实现了高性能通讯,支持tcp、http、websocket等协议,支持protobuf、json两种数据格式,支持以配置的形式轻松开启多端口网络服务。
- 支持RPC远程调用,支持以优雅的方式实现远程调用,支持调用超时重试、幂等调用。
- 封装了持久化层,提供数据访问和数据落地接口,支持异步新增、保存、删除数据,支持主键或指定其他字段进行数据缓存。
- 支持简单的ioc,业务层使用依赖注入实现逻辑。
- 封装了伪协程实现方案Promise,可用于解决地狱式回调等问题。
- 支持MVC、领域、ECS架构。

## 目录
- [更新说明](#更新说明)
- [环境介绍与安装说明](#环境介绍与安装说明)
- [快捷上手](#快捷上手)
- [创建项目](#创建项目)
- [项目结构](#项目结构)
- [运行项目](#运行项目)
- [框架介绍](#框架介绍)
- [组件介绍](#组件介绍)
- [注解介绍](#注解介绍)
- [核心方法介绍](#核心方法介绍)
- [异常介绍](#异常介绍)
- [协议介绍](#协议介绍)
- [Web介绍](#Web介绍)
- [运行机制](#运行机制)
- [其他介绍](#其他介绍)

## 更新说明
### 1.1.19 - 2024-08-23
1. 新增@ShardingKey注解,可对Repository进行分表,在test.sharding有相关例子。 - 2024-07-14
2. 修复Http协议下,上传文件WebFileUpload不能正确保存的问题。 - 2024-07-24
3. 优化Summer.getRandomClientRemote(),在调用ClientRemote时可自动轮训到可用的节点再发出RPC请求,感谢 [whxlxl](https://github.com/whxlxl) 大佬指出问题。 - 2024-07-29
4. 优化Client断线重连的方式。- 2024-07-29
5. 优化ModelView生成方式,由原来template->heapBuffer->directBuffer改为template->directBuffer,减少了一次内存拷贝。- 2024-08-17
6. 新增WebResponseHandler,可用于在HttpServer响应前修改WebView或HttpResponse。- 2024-08-23

### [1.1.18](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.18) - 2023-12-15
1. Summer启动时可选择加载的模块,通过Summer.addModuleNet()、addModuleDb、addModuleRedis加载模块,或者通过addModuleAll加载所有模块。

### [1.1.17](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.17) - 2023-09-20
1. 新增网络协议Custom,通过ProtocolCustomMgr设置ProtocolCustomHandler可实现自定义协议处理。 - 2023-03-09

### [1.1.16](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.16) - 2022-10-17
1. 修复了使用注解@Optional,当参数类型为基本类型会报错的问题,修改后可选的基本类型参数将提供默认参数值。
2. 注解@Optional,新增默认值。
3. 优化MySQL、Redis的Connection链路关闭权限,由发起者来关闭链路。
4. @Service支持事务管理,使用时需在方法上加上注解@Transaction,在SummerConfig中设置enableServiceRemoteProxy为true。
5. 移除Quartz任务调度框架,改用Spring的Cron表达式解析器配合ScheduledExecutorService实现定时任务调度。
6. 移除Druid数据库连接池框架,改用Hikari。

### [1.1.15](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.15) - 2022-09-19
1. 修复Http协议下,数据未发完链路关闭的问题。 - 2022-07-13
2. 将所有网络IO相关的buffer分配,由原来的非池化堆内缓存改为池化堆外缓存。 - 2022-09-19
3. WebView的onRender返回值调整,由原来的ChunkedInput改为WebViewRender,可使用默认实现DefaultWebViewRender。其中FileView,由原来的ChunkedFile改为FileRegion。 - 2022-09-19

### [1.1.14](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.14) - 2022-07-07
1. Http协议下,只能处理get/post方法,其他方法将直接关闭链路。 - 2022-02-08
2. 修复StringLine协议下会导致内存泄漏的问题,感谢 [whxlxl](https://github.com/whxlxl) 大佬指出问题。 - 2022-06-16
3. Http协议下,处理完请求发送响应后自动关闭链路。 - 2022-07-07

### [1.1.13](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.13) - 2022-01-24
1. 修复在RemoteTinyDispatchMgr抛出异常RemoteRuntimeException时,参数显示错误的问题。
2. 新增AsyncAddRepository,可用于日志异步插入。
3. 新增RepositoryEntity,仓库中的实体类实现此接口,即可直接执行 实体对象.add() 实体对象.save() 实体对象.remove()操作,而不再需要像以前 仓库对象.add(实体对象) 仓库对象.save(实体对象) 仓库对象.remove(实体对象),在一些场景下或许有助于提高开发速度。

### [1.1.12](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.12) - 2021-09-30
1. SummerConfig中新增字段enableServiceRemoteProxy,用以控制Summer启动时是否启用service和remote的代理。增强后的service、remote对于现在项目来说不一定有帮助,例如remote中的数据库事务处理操作,在异步仓库的环境下用处不大。故默认设置为不开启,如需启用请将此字段设置为true。
2. 新增@Dao注解下的类可使用@Autowired注解注入对象,为了使用起来更方便。之前的设计是从remote->service->dao,在业务不复杂的情况下,可以忽略service,直接remote->dao。
3. 对WebView进行简单的抽象。

### [1.1.11](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.11) - 2021-07-31
1. 新增网络协议,Tiny JSON。
2. 修复RemoteDispatchMgr.invoke解析方法参数,AutowireParam无效的问题。
3. 修复AsyncCacheRepository的removeAll不能达到期望效果的问题。在数据库还有旧数据时,刚启动程序先执行removeAll,再执行get或者list等查询操作,依旧可以查询到数据。由于removeAll是异步操作,所以会出现此问题,目前解决方案就是当执行removeAll时,任何查询操作只在缓存中查找不从数据库加载,只有removeAll执行完毕才恢复。

### [1.1.10](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.10) - 2021-06-30
1. Lifecycle新增destroy,触发时机为在EventBus关闭后,在Repository关闭前执行,所以destroy中不应该再抛出事件。
2. RepositoryBeanProcessor在极端条件下遍历columnHandlers可能出现并发问题,原因是DBUtils的ServiceLoader的遍历操作不是线程安全的,所以现调整为在类加载时先遍历一次ServiceLoader并存入ArrayList,此后只遍历ArrayList。

### [1.1.9](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.9) - 2021-05-31
1. 修复SessionHandler.handleReady在http协议下不生效的问题。

### [1.1.8](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.8) - 2021-04-30
1. 将框架中用到的LinkedList替换为ArrayList。[ArrayList与LinkedList对比](https://stackoverflow.com/questions/322715/when-to-use-linkedlist-over-arraylist-in-java/322742#322742)
2. RepositoryDao新增onLoadAfter、onSaveBefore方法,当对象从数据库加载后调用onLoadAfter,当对象在数据库写入前调用onSaveBefore。
3. Rpc轮询机制调整,优先使用可用的client。

### [1.1.7](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.7) - 2021-03-31
1. SessionHandler新增方法handleReady,在处理请求前触发此回调,与receive的不同之处是在此方法内可抛出异常,且在会话队列中执行。
2. 新增接口RemoteHandler、RemoteProtobufHandler,其中RemoteProtobufHandler仅用于protobuf协议。在使用注解@Remote的类上实现此接口。即可进行一些拦截或其他业务处理。与SessionHandler.handleReady的区别是,触发范围缩小,仅会对进入此类寻求处理方法的协议进行触发。
3. Repository新增支持过滤的list方法,新增stream方法获取数据。

### [1.1.6](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.6) - 2021-02-28
1. 新增注解@ParamPacking,当接口的参数过多时,可使用一个类包装起来,并在参数前加上此注解。(建议对外开放的接口,不要传递JSON格式的数据)
2. 新增WebTokenHandler,在http协议下可自定义token的生成和解析方式。
3. 修复Web模式下,设置ErrorView无法渲染的问题。
4. 新增WebContentTypes拓展名与内容类型的映射库。
5. 优化Web模式下,Url的解析方式。
6. 修复仓库模式,当字段设置为readOnly时,在某些情况下会构建出错误的sql语句的问题。
7. AsyncCacheRepositoryDao新增showDelaySaveInfo方法,可用于关闭延迟保存数据信息的输出。

### [1.1.5](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.5) - 2021-01-31
1. 修复在程序关闭时,异步事件中有推送异步消息的操作导致异常的问题。
2. 优化ServerPush,新增简单的调用接口。
3. 优化CacheRepositoryDao.list(Map optional),在筛选数据的过程中改用stream,在最后才进行collect操作。
4. 新增默认配置,在未明确指定配置文件路径的时候,并且默认路径下的配置文件不存在,则会启用默认配置。例如,在项目中引入summer依赖,无需本地配置文件,即可直接使用Summer.hot启动。
5. 通过Summer.hot启动时,未明确指定libPath时将不再通过默认路径"lib"去扫描加载jar。(mvn打包时可通过配置插件自动拷贝依赖以及在程序启动时加载指定依赖)

### [1.1.4](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.4) - 2020-12-31
1. 修复异步响应Summer.asyncResponse无法发送错误码。

### [1.1.3](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.3) - 2020-11-30
1. Repository中add操作不再执行insertSql语句,修改为replaceSql语句。
2. Repository增加listSingleCache方法,当实体只包含一个cacheKey时,可直接调用此方法查询数据。
3. Repository采用原子性、自旋等方式替换掉原有的同步锁。
4. AsyncCacheRepository中的add、remove增加版本号控制,定时器触发时只会对最新版本的数据进行数据库操作。
5. 新增@RequestMapping,可自定义请求映射的接口名称。
6. Repository新增removalAll方法。
7. EventBus新增订阅和派送方式,使用注解@AcceptEvent,无需设定事件名称,该注解下的方法只允许一个参数,并且该参数的类型将作为"事件名称"用于事件派送,详细请看test中的例子。
8. 修复RPC在一个Cluster下多个不同serverName时出现的BUG。感谢 [kingo132](https://github.com/kingo132) 大佬指出问题。

### [1.1.2](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.2) - 2020-10-31
1. 异步请求远程接口增加RemoteCallbackQuick接口,可用于接收响应的数据。
2. 新增meter包,可用于编写压测程序。
3. 新增promise包,可用于异步有序执行。
4. 优化SessionContextGroup,让SessionContext与Channel直接绑定。
5. 优化SessionQueueMgr。
6. 新增ecs包,实现了简单的ECS(Entity-Component-System)架构。
7. 优化RPC,在底层确保接口幂等性,所有client共用worker、event线程池。
8. CodeMsg、CodeException中的code由long调整为int。

### [1.1.1](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.1.1) - 2020-09-19
1. 新增协议,支持protobuf。
2. 新增标准的WebSocket协议,与原来的区别是去掉了包头的四个字节。
3. remote中的方法限定符如果不是public将不对远程开放。

### [1.0.18](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.18) - 2020-09-13
1. 心跳机制优化。
2. 用户请求默认在用户队列中进行处理,@SessionQueue废弃。

### [1.0.17](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.17) - 2020-09-08
1. SessionContext调整,新增属性token,token可以在用户登录以后手动设置为用户ID,以此作为用户的唯一标识。
2. SessionQueueMgr、SingleQueueMgr优化。SessionQueueMgr,不再使用直接使用SessionContext分配队列,改为使用SessionContext中的token分配队列,当token未设置时使用sessionId。
3. http协议下,sessionId不再作为用户的唯一标识,sessionId仅作为链路标识。当用户请求接口携带的cookie数据中不存在token时,响应时会下发通过UUID生成的32位字符串作为token,用户下一次请求时就会携带有token。通过sessionContext.getToken()获取token,通过sessionContext.clearToken()清空token。
4. 修复部分因为hashcode引发的问题。修复方式,将set改为list,重写hashcode,map中的key如果无法重写hashcode则对结构进行调整。
5. 修正SessionHandler中的accept拼写错误
6. test例子取消lombok依赖。

### [1.0.14](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.14) - 2020-05-18
1. 缓存仓库调整,当PrimaryKey为非自增模式时,使用CacheKey查询经历过remove,add的相同PrimaryKey的实体时,尽管实体中的CacheKey与查询的值不同也依旧能命中缓存,现将其进行修复。当主动remove时,会将存有对应PrimaryKey的CacheKey缓存清除。

### [1.0.13](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.13) - 2020-05-09
1. ServerBootstrap启动参数中的ChannelOption.SO_BACKLOG改为读取配置表,并将ChannelOption.ALLOCATOR设为PooledByteBufAllocator.DEFAULT
2. 仓库调整,增加getOrCreate方法。
3. 当项目未能在预期情况下运行时(例如端口被占用),及时终止进程。

### [1.0.10](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.10) - 2020-04-28
1. 当使用仓库时,实体的某个字段的类型如果为Array、Collection(List Set Queue)、Map、以及自定义的类时,需设定length。当length<=255,使用CHAR类型;当length<=16383,使用VARCHAR类型;当length>16383,使用TEXT类型。
2. SessionContext中的address分为directAddress和realAddress,其中directAddress为链路IP,realAddress通过Head中的"X-Forwarded-For"获取客户端真实IP,仅在HTTP、WEBSOCKET协议且在使用反向代理的情况下生效。
3. AsyncResponseMgr新增process方法可用于捕获异常以及自动发送响应。

### [1.0.3](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.3) - 2020-01-17
1. 日志调整,由原来的log4j改为logback,并且移除直接调用log4j的所有代码,完成了日志解耦,可自由替换成slf4j的其他实现。
2. 由于不再强制加载日志配置文件,Summer.hot移除了日志配置文件路径的参数。
3. Remote新增异步响应请求,可参考test中的例子。

### [1.0.0](https://mvnrepository.com/artifact/com.swingfrog.summer/summer/1.0.0) - 2019-12-27
使用mvn重构项目

### 0.9.1 - 2019-12-26
1. 异步缓存仓库调整,修复了异步add、异步remove在一起使用时,可能导致remove失败的问题,并进行了一定的优化,对同一对象先后进行add、remove,当发生在定时器同一执行期内,其操作相互抵消,不再进行数据库操作
2. Http协议下,抛出CodeException异常时,日志输出级别由error改为warn

### 0.9.0 - 2019-12-05
1. 缓存仓库调整,移除查询列表时按主键的hash code排序,以此提高性能。如果有业务需求,可以考虑在前端进行排序,分散后端压力。

### 0.8.0 - 2019-11-07
1. 异步缓存仓库调整,当有一个持久化对象,对它进行add、remove、add、remove操作时不能达到预期效果,因为id在第二次add时就发生变动,由于是同一个对象,所以当定时器触发写库时,第一个add的id已经变成了第二个add时的id,第一个remove的id也发生了变化。正确的用法是clone对象后再进行第二次add、remove,但考虑到有些场景是可以复用对象的,于是对异步缓存仓库层进行了调整,add或remove时会记录当时的id,再进行操作。

### 0.7.3 - 2019-10-25
1. 修复某些情况下请求接口时会出现参数错误的问题

### 0.7.2 - 2019-10-17
1. 修复部分线程池不能优雅关闭
2. EventMgr改名为EventBusMgr
3. 修改了业务线程池和推送线程池

### 0.7.1 - 2019-10-16
1. 修复持久化层仓库模式,list无法正确返回数据,并进行优化,当多次list之间的间隔时间小于缓存过期时间时,可直接命中缓存。
2. 从端口minor新增配置useMainServerThreadPool,默认为false,当置为true时,从端口将使用主端口的线程池 (监听线程池, 读写线程池, 业务线程池)。

### 0.7.0 - 2019-10-14
1. http协议下,实现了cookie机制,sessionId是识别唯一用户的标志,而sessionContext只是链路。当用户请求接口携带的cookie数据中不存在sessionId时,响应时会下发通过UUID生成的32位字符串作为sessionId,用户下一次请求时就会携带有sessionId。通过sessionContext.getSessionId()获取sessionId,通过sessionContext.clearSessionId()清空sessionId。
2. 新增一个用于统计接口调用情况的静态类RemoteStatistics。
3. 修复持久化层仓库模式,无法解析Date的问题。

### 0.6.0 - 2019-08-30
1. 移除之前实现的简单持久化层(2019.06.22的第三点)
2. 新增SessionContent.getWaitWriteQueueSize,可获得待写队列的长度
3. 接口SessionHandler新增抽象方法sending(SessionContext ctx),当尝试数据写入时会回调此方法,可配合第二点当待写队列长度过大时关闭会话
4. 新增持久化层,采用仓库模式(com.swingfrog.summer.db.repository),实体上使用仓库相关的注解,以及dao继承RepositoryDao,即可实现仓库模式,自动建表,无需手动写SQL语句。除了基础的仓库功能还有缓存仓库CacheRepositoryDao、异步缓存仓库AsyncCacheRepositoryDao,推荐使用异步缓存仓库,支持异步/同步插入、更新、删除,以及同步查询。

### 0.5.1 - 2019-06-22
1. 新增接口Lifecycle,当组件实现此接口后,即可在服务器启动时触发start方法,在服务器关闭时触发stop方法。
2. 新增方法 Set Summer.listDeclaredComponent(Class clazz),可用于采集容器内的组件,例如第一点正是使用此方法采集所有实现Lifecycle的组件。
3. 实现了一个简单的持久化层,支持缓存和异步写入,但对于结构有特定要求。使用时将实体继承AbstractDelayCacheEntity,dao继承DelayCacheDao,即可直接使用并自动建表。

### 0.5.0 - 2019-06-12
1. 支持一个进程启动多个服务端口,仅需对配置进行修改,详细请见下方服务器配置文件。在使用@ServerHandler时,默认监听主端口,若需要监听其他端口,可使用@ServerHandler(serverName)指定服务器名。

### 0.4.0 - 2019-05-22
1. 修复了http协议下请求资源css、js等,content-type错误的问题。
2. 注解@SingleQueue(key),新增通配符${arg},arg为Remote上的参数。
3. 修复注解@Synchronized不生效的问题。

### 0.3.1 - 2019-02-20
1. 新增Summer.getServerEventLoopGroup,用于获取服务器业务线程池
2. 新增Summer.getSessionQueueSize,用于获取会话队列长度
3. 优化SessionQueue、SingleQueue队列,不再分配新线程,将以队列的形式逐个提交到服务器业务线程中(在此特别感谢一位大哥的支持与协助)

### 0.3.0 - 2019-02-17
1. ClientRemote类,新增rsyncRemote方法,调用接口超时将自动重试直到成功为止。
2. ClientRemote类,新增getServerName方法,用于获取连接其他服务器的节点名称。
3. 新增Summer.getRemoteInvokeObjectWithRetry、Summer.getRandomRemoteInvokeObjectWithRetry,用于获取连接其他服务器的远程调用接口代理对象,超时将自动重试直到成功为止。

### 0.2.0 - 2019-01-28
1. 修复了,服务器之间远程调用可能出现丢包的问题,原因是消息id不能正确的递增,解决办法是修改了消息id的判断。
2. 当作为web服务器时,若接口返回的类型不是WebView,则将返数据序列化成Json,并返回TextView。

## 环境介绍与安装说明
JDK 1.8 以上

MySql 5.7 (仅供参考)

Redis 5.0 (仅供参考)

## 快捷上手
### 创建项目
1. 创建mvn项目
2. 添加summer到pom.xml
```

com.swingfrog.summer
summer
1.1.18

```

### 项目结构
- src
- lib
- config
- Template #Web项目
- WebContent #Web项目

#### src
##### 包结构
- com.test.summerDemo
- bean #实体
- constant #常量
- dao #数据库操作
- service #业务逻辑
- event #事件触发器
- handler #服务器会话回调
- push #推送接口
- remote #远程接口
- task #定时任务
- exception #异常信息
- manager #对象管理
- util #工具
- SummerDemoApp.java #启动类

##### 启动类
```java
package com.test.summerDemo;

import com.swingfrog.summer.app.Summer;
import com.swingfrog.summer.app.SummerApp;

public class SummerDemoApp implements SummerApp {

@Override
public void init() {

}

@Override
public void start() {

}

@Override
public void stop() {

}

public static void main(String[] args) throws Exception {
Summer.hot(new SummerDemoApp());
}

}
```
##### 其余的组件将在下文逐一介绍

#### lib
引用外部jar包请放在此目录下,并添加引用。

引用Summer.jar,此jar包依赖SummerServer库。

#### config
- db.properties #数据库配置文件
- redis.properties #缓存配置文件
- task.properties #任务配置文件
- server.properties #服务器配置文件

##### db.properties (hikari的配置文件)
```properties
driverClassName=com.mysql.cj.jdbc.Driver
jdbcUrl=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
username=root
password=123456
poolName=Test
minimumIdle=1
maximumPoolSize=10
connectionTimeout=30000
connectionTestQuery=SELECT 1

asyncCache.coreThread=1
```

##### redis.properties (jedis配置文件)
```properties
url=127.0.0.1
port=6379
timeout=3000
password=123456
blockWhenExhausted=true
evictionPolicyClassName=org.apache.commons.pool2.impl.DefaultEvictionPolicy
jmxEnabled=true
maxIdle=1
maxTotal=10
maxWaitMillis=30000
testOnBorrow=true
```

##### task.properties (配置文件)
```properties
coreThread=1
```

##### server.properties (服务器配置文件) [2020.05.09更新]
```properties
#服务器集群名称
server.cluster=Gate
#服务器节点名称
server.serverName=gate_s1
#绑定地址
server.address=127.0.0.1
#绑定端口
server.port=8828
#通讯协议
server.protocol=Http
#消息编码
server.charset=UTF-8
#消息密码
server.password=123456
#侦听线程数
server.bossThread=0
#读写线程数
server.workerThread=0
#业务线程数
server.eventThread=0
#消息最大长度 单位字节
server.msgLength=1024000
#心跳时间 单位秒
server.heartSec=40
#请求的间隔时间
server.coldDownMs=10
#是否开启连接白名单
server.allowAddressEnable=true
#白名单允许连接的地址
server.allowAddressList=127.0.0.1,127.0.0.2
#SOCKET: SO_BACKLOG
server.optionSoBacklog=1024

#服务器的其他端口列表
server.minorList=gate_s2

minor.gate_s2.cluster=Gate
minor.gate_s2.serverName=gate_s2
minor.gate_s2.address=127.0.0.1
minor.gate_s2.port=8080
minor.gate_s2.protocol=Http
minor.gate_s2.charset=UTF-8
minor.gate_s2.password=
minor.gate_s2.bossThread=0
minor.gate_s2.workerThread=0
minor.gate_s2.eventThread=0
minor.gate_s2.msgLength=1024000
minor.gate_s2.heartSec=40
minor.gate_s2.coldDownMs=10
minor.gate_s2.allowAddressEnable=false
minor.gate_s2.allowAddressList=
minor.gate_s2.optionSoBacklog=1024
#使用主端口的线程池 (监听线程池, 读写线程池, 业务线程池) 默认为false
minor.gate_s2.useMainServerThreadPool=true

#连接其他服务器的列表
server.clientList=account_s1,account_s2

#其他服务器的集群名称
client.account_s1.cluster=Account
#其他服务器的节点名称
client.account_s1.serverName=account_s1
#连接地址
client.account_s1.address=127.0.0.1
#连接端口
client.account_s1.port=8828
#通讯协议
client.account_s1.protocol=StringLine
#消息编码
client.account_s1.charset=UTF-8
#消息密码
client.account_s1.password=123456
#读写线程数
client.account_s1.workerThread=0
#业务线程数
client.account_s1.eventThread=0
#消息最大长度 单位字节
client.account_s1.msgLength=1024
#心跳时间 单位秒
client.account_s1.heartSec=20
#断线重连间隔时间 单位毫秒
client.account_s1.reconnectMs=100
#远程调用超时时间 单位毫秒
client.account_s1.syncRemoteTimeOutMs=5000
#连接数
client.account_s1.connectNum=1

client.account_s2.cluster=Account
client.account_s2.serverName=account_s2
client.account_s2.address=127.0.0.1
client.account_s2.port=8828
client.account_s2.protocol=StringLine
client.account_s2.charset=UTF-8
client.account_s2.password=123456
client.account_s2.workerThread=0
client.account_s2.eventThread=0
client.account_s2.msgLength=1024
client.account_s2.heartSec=20
client.account_s2.reconnectMs=100
client.account_s2.syncRemoteTimeOutMs=5000
client.account_s2.connectNum=1
```

### 运行项目

#### 开发环境
在eclipse中可直接运行或调试,启动类为SummerDemoApp.class

#### 生产环境
##### 打包
在Options中勾选Add directory entries。

注意,不要导出可运行的jar文件,因为会把lib中引用的jar和引用的库打包进jar中,造成jar体积巨大。
##### 项目结构
- SummerDemo
- SummerDemo.jar
- lib
- config
- Template
- WebContent
- SummerRuntime.jar
##### 使用SummerRuntime.jar运行
java -jar SummerRuntime.jar SummerDemo/SummerDemo.jar com.test.summerDemo.SummerDemoApp

## 框架介绍
### 组件介绍
SummerApp由辅助组件和主要组件组成,其中bean、constant、manager、util、exception为辅助组件,dao、service、event、handler、push、remote、task、app为主要组件。

#### bean
javabean、数据表的实体映射

#### constant
常量声明

#### manager
对象管理,使用时在类上方使用注解@Bean
```java
@Bean
public class LoginManager {

private ConcurrentHashMap accountIdMap = new ConcurrentHashMap<>();
private ConcurrentHashMap sessionContextMap = new ConcurrentHashMap<>();
//省略...

}
```
#### util
工具类

#### exception
异常信息声明

#### dao
数据库操作,类需继承BaseDao并使用注解@Dao
```java
@Dao
public class AccountDao extends BaseDao {

public Account getById(int id) {
return getBean("select * from t_account where id = ?", id);
}

}
```

```java
public abstract class BaseDao {

protected int update(String sql, Object... args){}
protected Long insertAndGetGeneratedKeys(String sql, Object... args){}
protected T getBean(String sql, Object... args) {}
protected List listBean(String sql, Object... args) {}
protected E getValue(String sql, Object... args) {}
protected List listValue(String sql, Object... args) {}
protected Map getMap(String sql, Object... args) {}
protected List> listMap(String sql, Object... args) {}
protected E getBeanByClass(String sql, Class clazz, Object... args) {}
protected List listBeanByClass(String sql, Class clazz, Object... args) {}

}
```

#### service
业务处理,使用时在类上方使用注解@Service

```java
@Service
public class AccountService {

@Autowired
private AccountDao accountDao;

public Account getAccountById(int accountId) {
return accountDao.getById(accountId);
}

}
```

#### event
事件处理器,使用时在类上方使用注解@EventHandler

在对应方法上方使用注解@BindEvent,参数为监听的事件的名称。也可使用@BindEvent(value = "事件名称", index = 1),index表示同名事件处理器的先后顺序,index小到大,顺序先到后。

如果该方法的返回值不为viod、null,则表示对该事件进行拦截,因此后面的事件处理器便不会收到通知。
```java
@EventHandler
public class FriendEvent {

@BindEvent("登录事件")
public void noticeFriend(int accountId) {}

}
```

#### handler
服务器会话回调,类需实现SessionHandler并使用注解@ServerHandler

此组件主要用于网关服务器,可对用户的连接和请求进行拦截或其他处理
```java
@ServerHandler
public class LoginHandler implements SessionHandler {

//是否允许该会话连接服务器 此处可进行黑名单拦截或白名单放行
@Override
public boolean accept(SessionContext sctx) {
return true;
}

//会话连接成功
@Override
public void added(SessionContext sctx) {

}

//会话心跳超时
@Override
public void heartTimeOut(SessionContext sctx) {

}

//会话发来的消息长度大于配置
@Override
public void lengthTooLongMsg(SessionContext sctx) {

}

//是否接收会话发来的消息
@Override
public boolean receive(SessionContext sctx, SessionRequest request) {
return true;
}

//是否接收会话发来的消息 用于protobuf
@Override
public boolean receive(SessionContext ctx, ProtobufRequest request) {
return true;
}

//会话断开连接
@Override
public void removed(SessionContext sctx) {

}

//会话发送重复消息
@Override
public void repetitionMsg(SessionContext sctx) {

}

//会话发送消息次数间隔小于配置
@Override
public void sendTooFastMsg(SessionContext sctx) {

}

//会话发来的消息无法解析
@Override
public void unableParseMsg(SessionContext sctx) {

}

}
```

#### push
推送接口,使用时在类上方使用注解@Push

用于将消息推送给连接本服务器的其他服务器或客户端
```java
@Push
public class DataPush {

public void pushDataToAll(DataPushMsg msg) {
Summer.getServerPush().asyncPushToAll(msg.getRemote(), msg.getMethod(), msg.getData());
}
}
```

#### remote
远程调用接口,使用时在类上方使用注解@Remote

SessionContext为调用此接口的会话,此参数可省略。

除了标记@Optional的参数外,皆为必填参数,如有遗漏会抛出异常。
```java
@Remote
public class AccountRemote {

@Autowired
private AccountService accountService;

public Account getAccount(SessionContext sctx, int accountId, @Optional remark) {
return accountService.getAccountById(accountId);
}

}
```

#### task
定时任务,使用时在类上方使用注解@Task

在对应的方法上方添加注解@CronTask、@IntervalTask,即表示该方法为一个任务。

@CronTask("cron 表达式")当时间满足cron表达式时执行该方法

@IntervalTask(1000)每隔1000毫秒执行该方法,或使用@IntervalTask(value = 1000, delay = 2000)2000毫秒后执行该方法,然后每隔1000毫秒执行该方法。
```java
@Task
public class StatTask {

@CronTask("0 0/5 * * * ? ")
public void onlineStatTask() {

}

@IntervalTask(1000)
public void updateXX() {

}

@IntervalTask(value = 1000, delay = 2000)
public void waitAndUpdate() {

}

}
```

#### app
app启动类,此类需实现SummerApp且添加程序入口main方法,并在main方法中调用启动框架。

Summer.hot会在后面提到。
```java
public class SupmersGateApp implements SummerApp {

private static final Logger log = LoggerFactory.getLogger(SupmersGateApp.class);

//框架初始化后回调
@Override
public void init() {
log.info("gate init");
}

//框架启动后回调
@Override
public void start() {
log.info("gate start");
}

//框架停止后回调
@Override
public void stop() {
log.info("gate stop");
}

public static void main(String[] args) throws Exception {
Summer.hot(new SupmersGateApp());
}

}
```

#### 组件之间的调用关系
remote 可调用service、util、manager、constant、bean、exception

push 可调用service、util、manager、constant、bean

handler 可调用service、util、manager、constant、bean

event 可调用service、util、manager、constant、bean

task 可调用service、util、manager、constant、bean、exception

service 可调用dao、service、util、manager、constant、bean、exception

util 可调用util、manager、constant、bean

manager 可调用util、manager、constant、bean

constant 无

bean 无



remote 由远程服务器或客户端调用

push 由远程服务器推送调用

handler 由框架根据会话信息调用

event 由事件驱动器调用

task 由任务处理器调用

### 注解介绍
注解主要分为两大类,组件类与辅助类。

#### 组件类注解
@Bean、@Dao、@Service、@Remote、@Push、@Task、@ServerHandler、@EventHandler

此类注解只用于类

使用此注解的类,在框架启动时,会自动扫描进容器并实例化常驻于内存中。

#### 辅助类注解
@Autowired、@Synchronized、@SingleQueue、@SessionQueue、@Optional、@Transaction、@CronTask、@IntervalTask、@BindEvent

此类注解只用于字段、方法、参数

#### @Bean
声明此类为容器中普通组件(manager、other)。
#### @Dao
声明此类为数据库操作(dao)。
#### @Service
声明此类为业务处理(service)。
#### @Remote
声明此类为远程接口(remote)。
#### @Push
声明此类为推送接口(push)。
#### @Task
声明此类为定时任务(task)。
#### @ServerHandler
声明此类为服务器会话回调(handler)。
#### @EventHandler
声明此类为事件处理器(event)。

#### @Autowired
在使用@Service、@Remote、@Push、@Task、@ServerHandler、@EventHandler这些注解的类中,其字段如果使用此注解,即可实现自动注入,注入的对象由容器提供。

组件中只有@Bean、@Dao、@Service支持被注入。
```java
@Remote
public class AccountRemote {

@Autowired
private AccountService accountService;

@Autowired
private StatService statService;

@Autowired
private ItemService itemService;

@Autowired
private DanService danService;

@Autowired
private PushManager pushManager;

}
```

#### @Synchronized
在使用@Service、@Remote、@Task、@EventHandler这些注解的类中,其方法如果使用此注解,即可为该方法上分布式锁。当该方法被调用时,会尝试获取锁,一直等到获取成功,执行完方法或抛异常会自动释放锁。

此锁适用于多服务器同步。
```java
@Remote
public class ShopRemote {

@Synchronized("购物锁")
public void buyGoods(int accountId, int goods) {}

}
```

#### @SingleQueue
在使用@Remote注解的类中,其方法如果使用此注解,在多个线程调用此方法是,会排进指定的队列中,依次完成调用。
```java
@Remote
public class StatRemote {

@SingleQueue("队列名称")
public void peopleOnline(int accountId) {}

// 使用 ${arg} arg为方法内参数名称
@SingleQueue("队列名称-${accountId}-${a}")
public void peopleOffline(int accountId, int a) {}

}
```

#### @Optional
在使用@Remote注解的类中,其方法参数如果使用此注解,即视为选填参数。
```java
@Remote
public class AccountRemote {

public Account getAccount(SessionContext sctx, int accountId, @Optional remark) {}

}
```
#### @Transaction
在使用@Remote、@Task、@EventHandler这些注解的类中,其方法如果使用此注解,即可开启mysql事务管理,方法执行完则提交事务,如抛出异常则回滚事务。
```java
@Remote
public class FriendRemote {

@Transaction
public void addFriend(int accountId, String name) {}

}
```

#### @CronTask
在使用@Task注解的类中,其方法参数如果使用此注解,即视为定时任务。

@CronTask("cron 表达式")
```java
@Task
public class StatTask {

@CronTask("0 0/5 * * * ? ")
public void onlineStatTask() {}

}
```
#### @IntervalTask
在使用@Task注解的类中,其方法参数如果使用此注解,即视为间隔任务。

@IntervalTask(1000) 立即执行并每1000毫秒再执行。

@IntervalTask(value = 1000, delay = 2000) 等待2000毫秒执行并每1000毫秒再执行。

```java
@Task
public class StatTask {

@IntervalTask(1000)
public void updateXX() {}

@IntervalTask(value = 1000, delay = 2000)
public void waitAndUpdate() {}

}
```
#### @BindEvent
在使用@EventHandler注解的类中,其方法参数如果使用此注解,即为该方法绑定了相应的事件,当有指定的事件发出时,事件驱动就会调用该方法。

@BindEvent("事件名称")

@BindEvent(value = "事件名称", index = 1) index表示同名事件处理器的先后顺序,
index小到大,顺序先到后。
```java
@EventHandler
public class FriendEvent {

@BindEvent("登录事件")
public void noticeFriendOnline(int accountId) {}

@BindEvent(value = "登出事件", index = 1)
public void noticeFriendoffline(int accountId) {}

}
```

### 核心方法介绍
核心方法可在任意地方使用。

#### Summer.hot
Summer框架启动方法
```java
public static void hot(SummerApp app) throws Exception {}
public static void hot(SummerApp app, String projectPackage) throws Exception {}
public static void hot(SummerConfig config) {}
```

#### Summer.sync
分布式锁
```java
public static void sync(String key, Runnable runnable) {}
```

#### Summer.execute
队列处理
```java
public static void execute(Object key, Runnable runnable) {}
```

#### Summer.addComponent
添加组件到容器
```java
public static void addComponent(Object obj) {}
```

#### Summer.removeComponent
从容器中移除组件
```java
public static void removeComponent(Object obj) {}
```

#### Summer.getComponent
从容器中获取组件
```java
public static T getComponent(Class> clazz) {}
```

#### Summer.listDeclaredComponent
从容器中获取组件
```java
public static List listDeclaredComponent(Class clazz) {}
```

#### Summer.getProxyInstance
创建代理对象
```java
public static T getProxyInstance(Object target, ProxyMethodInterceptor interceptor) {}
```

```java
public interface ProxyMethodInterceptor {

Object intercept(Object obj, Method method, Object[] args) throws Throwable;

}
```

#### Summer.autowired
组件注入,为目标对象中使用@Autowired注解的字段,进行对象注入。
```java
public static void autowired(Object obj) {}
```

#### Summer.getRedisSource
获取Redis源,可用于操作Redis。
```java
public static RedisSource getRedisSource() {}
```

#### Summer.getIntervalTask
创建间隔任务
```java
public static TaskTrigger getIntervalTask(long interval, long delay, String taskName, TaskJob taskJob) {}
```

#### Summer.getCronTask
创建定时任务
```java
public static TaskTrigger getCronTask(String cron, String taskName, TaskJob taskJob) {}
```

#### Summer.startTask
开始任务
```java
public static void startTask(TaskTrigger taskTrigger) {}
```

#### Summer.stopTask
停止任务
```java
public static void stopTask(TaskTrigger taskTrigger) {}
```

#### Summer.getClientRemote
通过集群名称和服务器节点名称获取连接其他服务器的远程调用接口对象
```java
public static ClientRemote getClientRemote(String cluster, String name) {}
```

```java
public class ClientRemote {

//异步调用远程接口
public void asyncRemote(String remote, String method, Object data, RemoteCallback remoteCallback) {}

//同步调用远程接口 (如果等待时间超出配置,则抛出异常)
public T syncRemote(String remote, String method, Object data, Type type) {}

}
```

#### Summer.getRandomClientRemote
通过集群名称,随机获取连接其他服务器的远程调用接口对象
```java
public static ClientRemote getRandomClientRemote(String cluster) {}
```

#### Summer.getRemoteInvokeObject
通过集群名称和服务器节点名称获取连接其他服务器的远程调用接口代理对象
```java
public static T getRemoteInvokeObject(String cluster, String name, Class> clazz) {}
```

#### Summer.getRemoteInvokeObjectWithRetry
通过集群名称和服务器节点名称获取连接其他服务器的远程调用接口代理对象,超时将自动重试直到成功为止
```java
public static T getRemoteInvokeObjectWithRetry(String cluster, String name, Class> clazz) {}
```

#### Summer.getRandomRemoteInvokeObject
通过集群名称,随机获取连接其他服务器的远程调用接口代理对象
```java
public static T getRandomRemoteInvokeObject(String cluster, Class> clazz) {}
```

#### Summer.getRandomRemoteInvokeObjectWithRetry
通过集群名称,随机获取连接其他服务器的远程调用接口代理对象,超时将自动重试直到成功为止
```java
public static T getRandomRemoteInvokeObjectWithRetry(String cluster, Class> clazz) {}
```

##### 账号服务器
```java
@Remote
public class FriendRemote {
@Autowired
private FriendService friendService;

@Transaction
public void addFriend(int accountId, String name) {
this.friendService.addFriend(accountId, name);
}
}
```

```java
public class AccountServerRemote {
public static FriendRemote getFriendRemote() {
return Summer.getRandomRemoteInvokeObject(ClusterConst.ACCOUNT, FriendRemote.class);
}
}
```

##### 网关服务器
将账号服务器的jar包引入网关服务器中,即可像调用本地方法一样调用远程接口。
```java
@Remote
public class FriendRemote {

@Autowired
private LoginManager loginManager;

public void addFriend(SessionContext sctx, String name) {
int accountId = loginManager.getAccountId(sctx);
AccountServerRemote.getFriendRemote().addFriend(accountId, name);
}

}
```

#### Summer.getServerPush
获取服务器推送接口对象
```java
public static ServerPush getServerPush() {}
```

```java
public class ServerPush {

//异步推送至该集群内所有服务器
public void asyncPushToClusterAllServer(String cluster, String remote, String method, Object data) {}

//同步推送至该集群内所有服务器
public void syncPushToClusterAllServer(String cluster, String remote, String method, Object data) {}

//异步推送至该集群内随机一台服务器
public void asyncPushToClusterRandomServer(String cluster, String remote, String method, Object data) {}

//同步推送至该集群内随机一台服务器
public void syncPushToClusterRandomServer(String cluster, String remote, String method, Object data) {}

//异步推送至该集群中指定的服务器
public void asyncPushToClusterThisServer(String cluster, String serverName, String remote, String method, Object data) {}

//同步推送至该集群中指定的服务器
public void syncPushToClusterThisServer(String cluster, String serverName, String remote, String method, Object data) {}

//异步推送至该会话
public void asyncPushToSessionContext(SessionContext sessionContext, String remote, String method, Object data) {}

//同步推送至该会话
public void syncPushToSessionContext(SessionContext sessionContext, String remote, String method, Object data) {}

//异步推送至部分会话
public void asyncPushToSessionContexts(List sessionContexts, String remote, String method, Object data) {}

//同步推送至部分会话
public void syncPushToSessionContexts(List sessionContexts, String remote, String method, Object data) {}

//异步推送至所有会话
public void asyncPushToAll(String remote, String method, Object data) {}

//同步推送至所有会话
public void syncPushToAll(String remote, String method, Object data) {}

}
```

#### Summer.closeSession
关闭会话
```java
public static void closeSession(SessionContext sctx) {}
```

#### Summer.getServerEventLoopGroup
获取服务器业务线程池
```java
public static EventLoopGroup getServerEventLoopGroup() {}
```

#### Summer.getSessionQueueSize
获取会话队列大小
```java
public static int getSessionQueueSize(SessionContext sctx){}
```

#### Summer.createCodeException
创建错误码异常对象
```java
public static CodeException createCodeException(long code, String msg) {}
public static CodeException createCodeException(CodeMsg msg, Object ...args) {}
```
#### Summer.createCodeMsg
创建错误码消息
```java
public static CodeMsg createCodeMsg(long code, String msg) {
```

#### Summer.getCluster
获取集群名称
```java
public static String getCluster() {}
```

#### Summer.getServerName
获取服务器节点名称
```java
public static String getServerName() {}
```

#### Summer.syncDispatch
同步发送消息事件
```java
public static void syncDispatch(String eventName, Object ...args) {}
```

#### Summer.asyncDispatch
异步发送消息事件
```java
public static void asyncDispatch(String eventName, Object ...args) {}
```

#### Summer.getWeb
获取Web相关接口
```java
public static WebMgr getWeb() {}
```

### 异常介绍
#### Error Code 100
调用异常 invoke error

当调用远程接口出现异常并且非自定义ErrorCode时,就会抛出此异常。

#### Error Code 101
远程接口不存在 remote not exist

#### Error Code 102
远程方法不存在 method not exist

#### Error Code 103
参数错误 parameter error

#### Error Code 104
远程接口受保护 remote was protected

#### Error Code 105
Protobuf不存在 protobuf not exist

#### 自定义 Error Code
##### 异常声明
```java
public class AccountException {

/**金币不足*/
public static final CodeMsg GOLD_NOT_ENOUGH = Summer.createCodeMsg(101005, "gold not enough, accountId[%s] own[%s] need[%s]");

}
```
##### 异常使用
建议只在remote和service中使用
```java
@Service
public class AccountService {

@Autowired
private AccountDao accountDao;

public int gainGold(int accountId, int gainGold) {
int ownGold = accountDao.getGoldByIdForUpdate(accountId);
int gold = ownGold + gainGold;
if (gold < 0) {
throw Summer.createCodeException(AccountException.GOLD_NOT_ENOUGH, accountId, ownGold, gainGold);
} else if (gold > AccountConst.GOLD_MAX) {
gold = AccountConst.GOLD_MAX;
}
accountDao.updateGold(accountId, gold);
return gold;
}

}
```

### 协议介绍
#### 消息定义
##### 请求消息
```json
{"id": 0, "remote": null, "method": null, "data": {}}
```
id 由客户端不断递增,由1开始

remote 远程接口 -> 类名

method 远程方法 -> 方法名

data 数据 -> 方法参数名与值

##### 响应消息
```json
{"code": 0, "id": 0, "remote": null, "method": null, "data": null, "time": 0}
```
code 错误码,为0标识无异常

id 与客户端请求消息的id一致

remote 请求的远程接口

method 请求的远程方法

data 返回的数据

time 时间戳

##### 推送消息
```json
{"code": 0, "id": 0, "remote": null, "method": null, "data": null, "time": 0}
```
code 为0

id 为0,可根据id是否为0来判断是否是推送消息

remote 推送接口

method 推送方法

data 推送的数据

time 时间戳

#### Protobuf消息定义
##### 请求消息
proto名称格式: 类名_Req_协议消息ID

例如: HeartBeat_Req_0

##### 响应消息
proto名称格式: 类名_Resp_协议消息ID

例如: HearBeat_Resp_0

##### 推送消息
proto名称格式: 类名_Push_协议消息ID

例如: Test_Push_100

#### StringLine协议
本协议支持加解密,支持服务器之间使用。消息格式为字符串,在字符串末尾加入\r\n,因此通过判断分隔符\r\n来区分消息。
```properties
#通讯协议
server.protocol=StringLine
```

#### WebSocket协议
本协议支持加解密,基于WebSocket协议。消息格式为二进制,数据包分为包头和包体,包头占四个字节,用来表示包体的长度。
```properties
#通讯协议
server.protocol=WebSocket
```

#### LengthField协议
本协议支持加解密,支持服务器之间使用。消息格式为二进制,数据包分为包头和包体,包头占四个字节,用来表示包体的长度。
```properties
#通讯协议
server.protocol=LengthField
```

#### WebSocket-Protobuf协议
本协议不支持加解密,基于WebSocket协议。消息格式为Protobuf,数据包分为包头和包体,包头占四个字节,用来表示包体的长度。包体前四个字节为协议消息ID,后面的字节为协议内容。
```properties
#通讯协议
server.protocol=WebSocket-Protobuf
```

#### LengthField-Protobuf协议
本协议不支持加解密,不支持服务器之间使用。消息格式为Protobuf,数据包分为包头和包体,包头占四个字节,用来表示包体的长度。
```properties
#通讯协议
server.protocol=LengthField-Protobuf
```

#### WebSocket-Standard协议
本协议支持加解密,基于WebSocket协议。消息格式为二进制,数据包只包含包体。
```properties
#通讯协议
server.protocol=WebSocket-Standard
```

#### WebSocket-Protobuf-Standard协议
本协议不支持加解密,基于WebSocket协议。消息格式为Protobuf,数据包只包含包体,包体前四个字节为协议消息ID,后面的字节为协议内容。
```properties
#通讯协议
server.protocol=WebSocket-Protobuf-Standard
```

#### Http协议
本协议不支持加解密,基于Http协议。
```java
@Remote
public class TestRemote {

public void test(String msg) {

}

}
```

```
//地址:端口/远程接口_远程方法?请求数据
http://127.0.0.1:8080/TestRemote_test?msg=hello
```

```properties
#通讯协议
server.protocol=Http
```

#### 消息加解密算法
##### WebSoccket与LengthField
```java
byte[] bytes = new byte[0];
String pass = "123456"; //密码由配置文件配置
int index = bytes.length % 10;
for (int i = 0; i < bytes.length; i++) {
if (index >= pass.length)
index = 0;
int res = bytes[i] ^ pass[index];
bytes[i] = (byte)res;
index++;
}
```
##### StringLine
```java
byte[] bytes = new byte[0];
String pass = "123456"; //密码由配置文件配置
int index = bytes.length % 10;
for (int i = 0; i < bytes.length; i++) {
if (index >= pass.length)
index = 0;
int res = bytes[i] ^ pass[index];
if (res != 10 && res != 13)
bytes[i] = (byte)res;
index++;
}
```

### Web介绍

#### Web配置管理
```java
public class WebMgr {

//重新加载模板
public void reloadTemplate() {}

//获取模板
public Template getTemplate(String templateName) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {}

//获取Web内容文件路径
public String getWebContentPath() {}

//设置Web内容文件路径
public void setWebContentPath(String webContentPath) {}

//获取模板文件路径
public String getTemplatePath() {}

//设置模板文件路径
public void setTemplatePath(String templatePath) {}

//获取内部视图渲染工厂
public InteriorViewFactory getInteriorViewFactory() {}

//设置内部视图渲染工厂
public void setInteriorViewFactory(InteriorViewFactory interiorViewFactory) {}

//获取主页路径
public String getIndex() {}

//设置主页路径
public void setIndex(String index) {}

//获取图标路径
public String getFavicon() {}

//设置图标路径
public void setFavicon(String favicon) {}

}
```

##### 内部视图渲染工厂
如需自定义空白视图或错误视图,只需继承此类覆盖相应的方法。
```java
public class InteriorViewFactory {

//空白视图
public BlankView createBlankView() {}

//错误视图
public ErrorView createErrorView(int status, long code, String msg) {}

//错误视图
public ErrorView createErrorView(int status, String msg) {}

}
```
#### WebView视图渲染
##### TextView
文字视图
```java
new TextView(String text);
```

##### JSONView
JSON视图
```java
new JSONView(JSON json);
```

##### FileView
文件视图
```java
new FileView(String fileName);
```

##### ModelView
模型视图
```java
ModelView model = new ModelView(String view);
model.put(String key, Object value);
```
view 模板地址

key 键

value 值

##### BlankView
空白视图
```java
new BlankView();
```

##### ErrorView
错误视图
```java
new ErrorView(int status, long code, String msg);
new ErrorView(int status, String msg);
```
status Http状态

code 错误码

msg 错误消息

#### Web异常介绍
##### Error Code 201
没有Web视图 not web view

#### 数据提交
```java
@Remote
public class UserRemote {

public JSONView add(String name, Integer age, @Optional remark) {
JSONObject json = new JSONObject();
json.put("flag", true);
return new JSONView(json);
}

}
```

##### get
```
http://127.0.0.1:8080/UserRemote_add?name=toke&age=22 //remark为选填
```
##### post
```html

;
;
;

```

#### 上传文件
```java
@Remote
public class FileRemote {

public void upload(WebFileUpload photo) {
photo.saveToFile("photos/");
}

}
```

```html

;

```

```java
public class WebFileUpload {

//获取文件名
public String getFileName() {}

//获取数据
public ByteBuf getByteBuf() {}

//保存到指定路径
public void saveToFile(String path) throws IOException {}

}

```

### 运行机制
通过Summer.hot启动框架。

初始化 -> 启动 -> 运行时 -> 停止

停止需要外部进行操作 kill -2 pid、kill -15 pid

#### 初始化
1. 加载jar包
2. 加载server配置
3. 加载redis配置
4. 加载数据库配置
5. 加载任务配置
6. 扫描组件类注解,实例化并添加进容器
7. 服务器管理初始化
8. 客户端管理初始化 (连接其他服务器)
9. 事件驱动初始化
10. 组件注入对象
11. service、remote、task生成代理对象

#### 启动
1. 服务器启动
2. 客户端连接 (连接其他服务器)
3. 任务启动

#### 运行时
##### 服务器管理
与会话保存心跳联系,心跳超时会通过handler通知。

##### 客户端管理 (连接其他服务器)
与其他服务器保存心跳联系,心跳超时后断线会自动重连。

##### 业务触发
两种方式触发业务处理,主动与被动。

主动,通过外部调用远程接口remote或会话的行为触发。

被动,通过内部任务处理器执行task触发。

#### 停止
停止一切

### 其他介绍
#### 负载均衡
随机远程调用和随机推送都是通过轮询实现
```java
public Client getClientWithNext() {
int size = clientList.size();
if (size == 0) {
return null;
}
if (size == 1) {
return clientList.get(0);
}
int n = next.getAndIncrement();
n = Math.abs(n);
n = n % size;
return clientList.get(n);
}
```

#### Redis操作
##### RedisSource
```java
public class RedisSource {

//通过key获取value
public String get(String key) {}

//设置key、value
public String put(String key, String value) {}

//设置key、value,返回是否成功
public boolean putAndSuccess(String key, String value) {}

//设置key、value,key过期时间
public String putWithTime(String key, int seconds, String value) {}

//设置key过期时间
public boolean setExpireTime(String key, int seconds) {}

//取消key过期时间
public boolean delExpireTime(String key) {}

//获取key剩余时间
public long getRemainTime(String key) {}

//判断key是否存在
public boolean exists(String key) {}

//移除key
public boolean remove(String key) {}

//获取key的类型
public String getType(String key) {}

//获取map
public RedisMap getMap(String key) {}

//获取list
public RedisList getList(String key) {}

//获取set
public RedisSet getSet(String key) {}

//获取deque
public RedisDeque getDeque(String key) {}

//清除redis
public void clear() {}
}
```

##### RedisMap
封装了Redis的Hash
```java
public class RedisMap implements Map {}
```

##### RedisList
封装了Redis的List
```java
public class RedisList extends RedisCollection implements List {}
```

##### RedisSet
封装了Redis的Set
```java
public class RedisSet implements Set {}
```

##### RedisDeque
封装了Redis的List
```java
public class RedisDeque extends RedisCollection implements Deque {}
```

##### RedisCollection
```java
public abstract class RedisCollection implements Collection {}
```