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. 聊天隊列會單獨使用秒定時器
    6. 數據解碼
      1. 協議ID
      2. 參數長度
      3. 是否壓縮
      4. 參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM