Skip to content
这是一个支持分布式和集群的java游戏服务器框架,可用于开发棋牌、回合制等游戏。基于netty实现高性能通讯,支持tcp、http、websocket等协议。支持消息加解密、攻击拦截、黑白名单机制。封装了redis缓存、mysql数据库的连接与使用。轻量级,便于上手。
Branch: master
Clone or download
Latest commit a113c30 Apr 11, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
SummerServer Add files via upload Dec 5, 2018
demo/SummerDemo add simple demo Apr 11, 2019
jar update session and single queue Feb 19, 2019
src/com/swingfrog/summer update session and single queue Feb 19, 2019
README.md update session and single queue Feb 19, 2019

README.md

Summer

这是一个支持分布式和集群的java游戏服务器框架,可用于开发棋牌、回合制等游戏。基于netty实现高性能通讯,支持tcp、http、websocket等协议。支持消息加解密、攻击拦截、黑白名单机制。封装了redis缓存、mysql数据库的连接与使用。轻量级,便于上手。

目录

  • 前言
  • 环境介绍与安装说明
  • 快捷上手
    • 创建项目
    • 项目结构
    • 运行项目
  • 框架介绍
    • 组件介绍
    • 注解介绍
    • 核心方法介绍
    • 异常介绍
    • 协议介绍
    • Web介绍
    • 运行机制
    • 其他介绍

前言

更新

2019.02.20

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

2019.02.17

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

2019.01.28

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

环境介绍与安装说明

JDK 1.8 以上
MySql 5.7 (仅供参考)
Redis 5.0 (仅供参考)
IDE: eclipse (仅供参考)
将SummerServer库添加至UserLibraries

SummerServer库

asm-6.2.jar
cglib-3.2.7.jar
commons-dbutils-1.7.jar
commons-pool2-2.4.2.jar
druid-1.1.10.jar
fastjson-1.2.47.jar
freemarker-2.3.23.jar
javassist-3.22.0-GA.jar
jedis-2.9.0.jar
log4j-1.2.17.jar
mysql-connector-java-5.1.20-bin.jar
netty-all-4.1.23.Final.jar
quartz-2.3.0.jar
slf4j-api-1.7.25.jar
slf4j-log4j12-1.7.25.jar

快捷上手

创建项目

  1. 创建普通的java project项目
  2. 为当前项目添加SummerServer库

项目结构

  • 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 #启动类
启动类
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 #缓存配置文件
  • log.properties #日志配置文件
  • task.properties #任务配置文件
  • server.properties #服务器配置文件
db.properties (druid的配置文件)
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
username=root
password=123456
filters=stat
initialSize=2
maxActive=300
maxWait=60000
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 1
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
poolPreparedStatements=false
maxPoolPreparedStatementPerConnectionSize=200
redis.properties (jedis配置文件)
url=127.0.0.1
port=6379
timeout=3000
password=123456
blockWhenExhausted=true
evictionPolicyClassName=org.apache.commons.pool2.impl.DefaultEvictionPolicy
jmxEnabled=true
maxIdle=8
maxTotal=200
maxWaitMillis=100000
testOnBorrow=true
log.properties (log4j配置文件)
log4j.rootLogger=DEBUG,C
log4j.logger.org.quartz=OFF
log4j.logger.com.alibaba.druid=DEBUG
log4j.logger.io.netty=OFF

log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.C.Target=System.out
log4j.appender.C.layout=com.swingfrog.summer.log.ColorPatternLayout
log4j.appender.C.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss\:SSS} [%t] %p [] %m %n

log4j.appender.F=org.apache.log4j.DailyRollingFileAppender
log4j.appender.F.File=log/container
log4j.appender.F.Append=true
log4j.appender.F.DatePattern='.'yyyy-MM-dd
log4j.appender.F.layout=com.swingfrog.summer.log.ColorPatternLayout
log4j.appender.F.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss\:SSS} [%t] %p [] %m %n
task.properties (quartz配置文件)
org.quartz.scheduler.instanceName=Task
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.scheduler.wrapJobExecutionInUserTransaction=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=10
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
server.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

#连接其他服务器的列表
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

@Bean
public class LoginManager {

	private ConcurrentHashMap<Integer, SessionContext> accountIdMap = new ConcurrentHashMap<>();
	private ConcurrentHashMap<SessionContext, Integer> sessionContextMap = new ConcurrentHashMap<>();
	//省略...
	
}

util

工具类

exception

异常信息声明

dao

数据库操作,类需继承BaseDao并使用注解@Dao

@Dao
public class AccountDao extends BaseDao<Account> {

    public Account getById(int id) {
		return getBean("select * from t_account where id = ?", id);
	}
	
}
public abstract class BaseDao<T> {

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

service

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

@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,则表示对该事件进行拦截,因此后面的事件处理器便不会收到通知。

@EventHandler
public class FriendEvent {

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

handler

服务器会话回调,类需实现SessionHandler并使用注解@ServerHandler
此组件主要用于网关服务器,可对用户的连接和请求进行拦截或其他处理

@ServerHandler
public class LoginHandler implements SessionHandler {
	
	//是否允许该会话连接服务器 此处可进行黑名单拦截或白名单放行
	@Override
	public boolean accpet(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;
	}

    //会话断开连接
	@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
用于将消息推送给连接本服务器的其他服务器或客户端

@Push
public class DataPush {
	
	public void pushDataToAll(DataPushMsg msg) {
		Summer.getServerPush().asyncPushToAll(msg.getRemote(), msg.getMethod(), msg.getData());
	}
}

remote

远程调用接口,使用时在类上方使用注解@Remote
SessionContext为调用此接口的会话,此参数可省略。
除了标记@Optional的参数外,皆为必填参数,如有遗漏会抛出异常。

@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毫秒执行该方法。

@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会在后面提到。

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支持被注入。

@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这些注解的类中,其方法如果使用此注解,即可为该方法上分布式锁。当该方法被调用时,会尝试获取锁,一直等到获取成功,执行完方法或抛异常会自动释放锁。
此锁适用于多服务器同步。

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

@SingleQueue

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

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

@SessionQueue

在使用@Remote注解的类中,其方法如果使用此注解,在多个线程调用此方法是,会排进当前请求者的会话队列中,依次完成调用。

@Remote
public class ItemRemote {
    
    @SessionQueue
    public void listItem(int accountId) {}
}

@Optional

在使用@Remote注解的类中,其方法参数如果使用此注解,即视为选填参数。

@Remote
public class AccountRemote {

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

@Transaction

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

@Remote
public class FriendRemote {

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

@CronTask

在使用@Task注解的类中,其方法参数如果使用此注解,即视为定时任务。
@CronTask("cron 表达式")

@Task
public class StatTask {

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

@IntervalTask

在使用@Task注解的类中,其方法参数如果使用此注解,即视为间隔任务。
@IntervalTask(1000) 立即执行并每1000毫秒再执行。
@IntervalTask(value = 1000, delay = 2000) 等待2000毫秒执行并每1000毫秒再执行。

@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小到大,顺序先到后。

@EventHandler
public class FriendEvent {

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

核心方法介绍

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

Summer.hot

Summer框架启动方法

public static void hot(SummerApp app) throws Exception {}
public static void hot(SummerApp app, String projectPackage) throws Exception {}
public static void hot(SummerApp app, String projectPackage, String libPath,
			String serverProperties, String logProperties, 
			String redisProperties, String dbProperties, String taskProperties) throws Exception {}

Summer.sync

分布式锁

public static void sync(String key, Runnable runnable) {}

Summer.execute

队列处理

public static void execute(Object key, Runnable runnable) {}

Summer.addComponent

添加组件到容器

public static void addComponent(Object obj) {}

Summer.removeComponent

从容器中移除组件

public static void removeComponent(Object obj) {}

Summer.getComponent

从容器中获取组件

public static <T> T getComponent(Class<?> clazz) {}

Summer.getProxyInstance

创建代理对象

public static <T> T getProxyInstance(Object target, ProxyMethodInterceptor interceptor) {}
public interface ProxyMethodInterceptor {

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

Summer.autowired

组件注入,为目标对象中使用@Autowired注解的字段,进行对象注入。

public static void autowired(Object obj) {}

Summer.getRedisSource

获取Redis源,可用于操作Redis。

public static RedisSource getRedisSource() {}

Summer.getIntervalTask

创建间隔任务

public static TaskTrigger getIntervalTask(long interval, long delay, String taskName, TaskJob taskJob) {}

Summer.getCronTask

创建定时任务

public static TaskTrigger getCronTask(String cron, String taskName, TaskJob taskJob) {}

Summer.startTask

开始任务

public static void startTask(TaskTrigger taskTrigger) {}

Summer.stopTask

停止任务

public static void stopTask(TaskTrigger taskTrigger) {}

Summer.getClientRemote

通过集群名称和服务器节点名称获取连接其他服务器的远程调用接口对象

public static ClientRemote getClientRemote(String cluster, String name) {}
public class ClientRemote {

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

Summer.getRandomClientRemote

通过集群名称,随机获取连接其他服务器的远程调用接口对象

public static ClientRemote getRandomClientRemote(String cluster) {}

Summer.getRemoteInvokeObject

通过集群名称和服务器节点名称获取连接其他服务器的远程调用接口代理对象

public static <T> T getRemoteInvokeObject(String cluster, String name, Class<?> clazz) {}

Summer.getRemoteInvokeObjectWithRetry

通过集群名称和服务器节点名称获取连接其他服务器的远程调用接口代理对象,超时将自动重试直到成功为止

public static <T> T getRemoteInvokeObjectWithRetry(String cluster, String name, Class<?> clazz) {}

Summer.getRandomRemoteInvokeObject

通过集群名称,随机获取连接其他服务器的远程调用接口代理对象

public static <T> T getRandomRemoteInvokeObject(String cluster, Class<?> clazz) {}

Summer.getRandomRemoteInvokeObjectWithRetry

通过集群名称,随机获取连接其他服务器的远程调用接口代理对象,超时将自动重试直到成功为止

public static <T> T getRandomRemoteInvokeObjectWithRetry(String cluster, Class<?> clazz) {}
账号服务器
@Remote
public class FriendRemote {
	@Autowired
	private FriendService friendService;

	@Transaction
	public void addFriend(int accountId, String name) {
		this.friendService.addFriend(accountId, name);
	}
}
public class AccountServerRemote {
    public static FriendRemote getFriendRemote() {
		return Summer.getRandomRemoteInvokeObject(ClusterConst.ACCOUNT, FriendRemote.class);
	}
}
网关服务器

将账号服务器的jar包引入网关服务器中,即可像调用本地方法一样调用远程接口。

@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

获取服务器推送接口对象

public static ServerPush getServerPush() {}
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<SessionContext> sessionContexts, String remote, String method, Object data) {}

    //同步推送至部分会话
	public void syncPushToSessionContexts(List<SessionContext> 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

关闭会话

public static void closeSession(SessionContext sctx) {}

Summer.getServerEventLoopGroup

获取服务器业务线程池

public static EventLoopGroup getServerEventLoopGroup() {}

Summer.getSessionQueueSize

获取会话队列大小

public static int getSessionQueueSize(SessionContext sctx){}

Summer.createCodeException

创建错误码异常对象

public static CodeException createCodeException(long code, String msg) {}
public static CodeException createCodeException(CodeMsg msg, Object ...args) {}

Summer.createCodeMsg

创建错误码消息

public static CodeMsg createCodeMsg(long code, String msg) {

Summer.getCluster

获取集群名称

public static String getCluster() {}

Summer.getServerName

获取服务器节点名称

public static String getServerName() {}

Summer.syncDispatch

同步发送消息事件

public static void syncDispatch(String eventName, Object ...args) {}

Summer.asyncDispatch

异步发送消息事件

public static void asyncDispatch(String eventName, Object ...args) {}

Summer.getWeb

获取Web相关接口

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

异常声明
public class AccountException {

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

建议只在remote和service中使用

@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;
	}
	
}

协议介绍

消息定义

请求消息
{"id": 0, "remote": null, "method": null, "data": {}}

id 由客户端不断递增,由1开始
remote 远程接口 -> 类名
method 远程方法 -> 方法名
data 数据 -> 方法参数名与值

响应消息
{"code": 0, "id": 0, "remote": null, "method": null, "data": null, "time": 0}

code 错误码,为0标识无异常
id 与客户端请求消息的id一致
remote 请求的远程接口
method 请求的远程方法
data 返回的数据
time 时间戳

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

code 为0
id 为0,可根据id是否为0来判断是否是推送消息
remote 推送接口
method 推送方法
data 推送的数据
time 时间戳

StringLine协议

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

#通讯协议
server.protocol=StringLine

WebSocket协议

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

#通讯协议
server.protocol=WebSocket

LengthField协议

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

#通讯协议
server.protocol=LengthField

Http协议

本协议不支持加解密,基于Http协议。

@Remote
public class TestRemote {
    
    public void test(String msg) {
        
    }
    
}
//地址:端口/远程接口_远程方法?请求数据
http://127.0.0.1:8080/TestRemote_test?msg=hello
#通讯协议
server.protocol=Http

消息加解密算法

WebSoccket与LengthField
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
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配置管理

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) {}
	
}
内部视图渲染工厂

如需自定义空白视图或错误视图,只需继承此类覆盖相应的方法。

public class InteriorViewFactory {

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

WebView视图渲染

TextView

文字视图

new TextView(String text);
JSONView

JSON视图

new JSONView(JSON json);
FileView

文件视图

new FileView(String fileName);
ModelView

模型视图

ModelView model = new ModelView(String view);
model.put(String key, Object value);

view 模板地址
key 键
value 值

BlankView

空白视图

new BlankView();
ErrorView

错误视图

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

数据提交

@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
<form action="http://127.0.0.1:8080/UserRemote_add" method="post">
	<input type="text" name="name"/>;
	<input type="text" name="age"/>;
	<input type="text" name="remark"/>;
	<input class="button" type="submit"/>
</form>

上传文件

@Remote
public class FileRemote {
    
    public void upload(WebFileUpload photo) {
        photo.saveToFile("photos/");
    }
    
}
<form action="http://127.0.0.1:8080/FileRemote_upload" method="post" enctype="multipart/form-data">
	<input type="file" name="photo"/>;
	<input class="button" type="submit"/>
</form>
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触发。

停止

停止一切

其他介绍

负载均衡

随机远程调用和随机推送都是通过轮询实现

    public Client getClientWithNext() {
		int size = clientGroupList.size();
		if (size > 0) {
			if (size == 1) {
				return clientGroupList.get(0).getClientWithNext();
			}
			next ++;
			next = next % size;
			return clientGroupList.get(next % size).getClientWithNext();
		}
		return null;
	}

Redis操作

RedisSource
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

public class RedisMap implements Map<String, String> {}
RedisList

封装了Redis的List

public class RedisList extends RedisCollection implements List<String> {}
RedisSet

封装了Redis的Set

public class RedisSet implements Set<String> {}
RedisDeque

封装了Redis的List

public class RedisDeque extends RedisCollection implements Deque<String> {}
RedisCollection
public abstract class RedisCollection implements Collection<String> {}
You can’t perform that action at this time.