背景
一直想自己试试设计一个只属于自己的小框架,于是就有了这个项目。
代码地址
https://coding.net/u/mich/p/MiniServer/git
项目说明
该项目主要将每个服务都配置一个消息队列,服务间通过消息进行传递,同时提供了控制台指令,进行服务的管理,实现一些后台的工作(主要web太麻烦了,所以控制台输入最省力),该项目只处理过一些小型后台任务,未在正式大型项目中实际使用过!
未来展望
1. 以后估计会将以往做过的微博用户数据抓取,tower对接,股票数据抓取及分析等已开发的项目在该框架的基础上实现(事实是原来以有一套类似小框架,但是后来被我嫌弃,现在重写了)
2.可能会将该项目分布式,通过zookeeper分布式管理所有的服务
3.加入实时热更新的功能,这也是服务消息化的主要原因
模块介绍
主要模块介绍就在上方的git地址看吧,此处省略
使用介绍
git上贴图不方便,说明什么的还是这里介绍吧。这里简单介绍一下example文件夹内容。
主要实现功能就是抽奖功能,在奖池中设置几个奖品,然后玩家多线程的去同时获取奖品
1. PrizeServer
该类就设置一个prize属性,作为奖品的数量,由于只有一个奖池,所以此服务设置为MiniServerType.SINGLETON,同时设置一下服务的名称name(其实不设置也可以默认为类名),然后设置一个初始化函数打上 @MiniServerInit注解,把奖品的数量设置为2。对外,我设置了一个抽奖的方法drawPrize()判断是不是有奖品,如果没有就返回-1
package example.server;
import com.basic.stableserver.MenuMethod;import com.basic.stableserver.MiniServerInfo;import com.basic.stableserver.MiniServerInit;import com.basic.stableserver.MiniServerType;import com.basic.utils.Utils; /** * Created by Mich on 17/7/7. */@MiniServerInfo(value = MiniServerType.SINGLETON, name = "PrizeServer")public class PrizeServer { private int prize; @MenuMethod public int drawPrize() { if (prize == 0) { return -1; } prize -= 1; return Utils.getRandom(); } @MenuMethod public int getPrize() { return prize; } @MiniServerInit public void init() { this.prize = 2; }}
2. PlayerServer
玩家服务,由于玩家不同于奖池只有一个,玩家会有很多个,所以设置了@MiniServerInfo(value = MiniServerType.PROTOTYPE, name = "PlayerServer", id = "id"),同样为了区分每个玩家的信息,加入了id="id",除了id,同时设置了money.同样我对玩家做了些初始化的操作,设置了钱,同时输出了便于测试识别,退出时,我也输出了日志。对外,我也设置了几个方法,主要为draw()抽奖方法,通过获取奖池服务,call("drawPrize")来阻塞住消息,最后判断返回获得了什么奖品,同时输出奖品
package example.server; import com.basic.stableserver.*; /** * Created by Mich on 17/7/7. */@MiniServerInfo(value = MiniServerType.PROTOTYPE, name = "PlayerServer", id = "id")public class PlayerServer { private int id; private int money; @MenuMethod public int removeMoney(Integer money) { this.money -= money; System.out.println("id : " + id + " rest " + this.money); return this.money; } @MenuMethod public int draw() { MiniServer prizeServer = MiniServerController.getInstance().getMiniServer(PrizeServer.class); this.money -= 100; int prize = (Integer) prizeServer.call("drawPrize"); if (prize == -1) { this.money += 100; System.out.println("id : " + id + " not get prize,rest money:" + this.money); } else { System.out.println("id : " + id + " get prize " + prize + ",rest money:" + this.money); } return prize; } @MenuMethod public void logout() { MiniServerController.getInstance().unregister(this.getClass(), this.id); } @MenuMethod public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } public void setId(int id) { this.id = id; } public int getId() { return id; } @MiniServerInit public void init() { this.money = 10000; System.out.println("id : " + id + " coming, rest " + this.money); } @MiniServerDestroy public void destroy() { System.out.println("id : " + id + " leave, rest " + this.money); }}
3.Start
在玩家和奖池都设计完后,就是启动类了。首先我先初始化最核心的管理类MiniServerController,然后再管理类加载完之后初始化控制台管理服务,此时会将所有的服务加载到此InputServer中,便于控制台管理(其实此样例有没有无所谓)。先获得玩家服务,然后初始化5个玩家,加入到玩家服务中(事实上是可以多线程添加的,但是为了展示抽奖的效果,就同步添加了)。然后多线程的对玩家服务传递info的抽奖消息,最后玩家在退出,此处由于是异步的,所以有可能玩家会先退出再抽奖,但是没关系,系统做了处理,对于离开的玩家有两种特殊处理情形,一种为玩家呼叫退出时,还有一部分消息滞留在消息队列中,此时玩家并不会直接退出,而是等此部分消息处理完再退出,同时在呼叫退出时,此时队列不再接受此玩家的所有消息,另一种为玩家退出后,过一会儿又回来了(可能是断线重连),此时如果玩家由于之前退出时还有消息没处理完而没有退出的,那就像什么事都没发生过一样,继续保留。由于不知道玩家哪一条消息式最后一条消息,而每个服务只有一个消息队列,所以我采取的策略是在处理下一条指令时判断指令接受时间与退出时间作对比,所以为了示例,我最后添加了玩家30的消息处理,以防玩家没有退出(此处以后会改)
package example; import com.basic.stableserver.InputServer; import example.server.PlayerServer; import com.basic.stableserver.MiniServer; import com.basic.stableserver.MiniServerController; /** * Created by Mich on 17/7/7. */ public class Start { public static void main(String[] args) { MiniServerController miniServerController = MiniServerController.getInstance(); miniServerController.init(); InputServer inputServer = new InputServer(); inputServer.start(); MiniServer playerMiniServer = miniServerController.getMiniServer(PlayerServer.class); int playersNum = 5; for (int i = 0; i < playersNum; i++) { PlayerServer playerServer = new PlayerServer(); playerServer.setId(i); playerMiniServer.addSubject(playerServer); } for (int i = 0; i < 5; i++) { final int tmp = i; Thread thread = new Thread(new Runnable() { @Override public void run() { playerMiniServer.info(tmp, "draw"); } }); thread.start(); } for (int i = 0; i < playersNum; i++) { miniServerController.unregister(PlayerServer.class, i); } PlayerServer playerServer = new PlayerServer(); playerServer.setId(30); playerMiniServer.addSubject(playerServer); playerMiniServer.info(30, "draw"); } }
最后看一下执行结果
最先看见的是玩家的进入,之后由于玩家3和玩家2退出指令比抽奖早,所以遗憾的没有尝试抽奖就退出了,而玩家1和30由于玩家0和4抽取到了奖品而奖品池只有两份奖品而最终没有获得奖品。