java--游戏后端--项目开发总结--服务端

  1. 功能
    1. 客户端交互
      1. 客户端获取服务器列表客户端
      2. 获取公告
    2. CDN服务
      1. 资源包上传
      2. 更新资源
    3. 服务端交互
      1. 服务端验证登陆
      2. 支付分发给服务端
    4. 数据配置
    5. GM功能
    6. 数据统计
  2. 技术
    1. 高级语言--Java8
    2. 框架--SpringBoot2.0
    3. 项目管理--Gradle
    4. 缓存--redis
    5. 数据库Mysql5.6
    6. 通讯框架--Netty
    7. 传输框架--Protostuff
  3. 启动流程
    1. 不占用端口启动
    2. 经过注解获取协议进行初始化
    3. 初始化线程池用于有序处理客户端消息
    4. 初始化游戏数据
    5. 向后台获取游戏配置数据
    6. 初始化定时任务用于定时更新数据
    7. 启动Netty
  4. 关闭流程
    1. 实现接口ApplicationListener<ContextClosedEvent>
    2. 配置中注册监听
    3. 服务器关闭前处理临时数据落地到数据库
  5. 开发总结
    1. 关于缓存
      1. 缓存使用的redis
      2. 使用Jackson2JsonRedisSerializer替换了value的序列化与反序列化,可是对应map的序列化若是有排序要求,即便使用ConcurrentSkipListMap有序的集合,依然在反序列化的时候回出现顺序错误,在redis可视化工具看到的数据顺序是对的
    2. 关于成就设计
      1. 成就采用的是spring自带的事件系统
      2. 业务处理完回到数据完成后能够提交事件
      3. 在成就或任务系统中对事件进行处理
    3. 关于线程池
      1. 重写了拒绝策略
      2. /**
             * 在线程池提交任务的最后一步——被线程池拒绝的任务,能够在拒绝后调用队列的put()方法,让任务的提交者阻塞,直到队列中任务被被线程池执行后,队列有了多余空间,调用方才返回
             */
            private static class BlockCallerPolicy implements RejectedExecutionHandler {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    try {
                        executor.getQueue().put(r);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    4. 关于业务初始化
      1. 使用了接口
      2. /**
         * 初始化接口
         *
         * @date :2019/3/14 17:15
         */
        public interface InitBaseHandler {
            /**
             * 实现此方法将在服务器启动时进行初始化操做
             */
            void init();
        }
      3. 此接口能够在应用初始化时调用,将调用实现此接口的全部实现类
      4.         LogHandler.info("no2.初始化游戏数据......");
                applicationContext.getBeansOfType(InitBaseHandler.class).values().forEach(InitBaseHandler::init);
    5. 关于定时器
      1. 先使用的每分钟一次的定时器
      2.     /**
             * 定时更新
             */
            @Override
            public void init() {
                LogHandler.info("初始化定时任务");
                int second = Calendar.getInstance().get(Calendar.SECOND);
                ExecutorHandler.scheduledExecutorService.scheduleAtFixedRate(() -> {
                    Calendar calendar = Calendar.getInstance();
                    int minute = calendar.get(Calendar.MINUTE);
                    if (minute % INTERVAL == 0) {
                        playerService.updatePlayer();
                        playerService.updatePlayerData();
                        globalService.updateGlobalData();
                    }
                }, 60 - second, 60, TimeUnit.SECONDS);
            }
      3. 后期会优化为扩展性更高的相似linux的cron月日时分定时器
        1. 没有考虑年
        2. 若是须要能够增长季度
        3. 没有考虑秒
        4. 聊天队列会单独使用秒定时器
相关文章
相关标签/搜索