当前位置: 首页 > news >正文

使用SpringBoot进行游戏服务器开发

背景:

之前一直只考虑用JavaSe进行游戏服务器开发,目前项目使用了Spring,发现还是非常好的,好处如下:

        好处1:依赖注入非常方便,我们只使用Spring最基本的功能即可,这样子就算是有一些模块不使用Spring管理也是非常方便的,因为我现在已经能轻松控制住Spring容器的声明周期。

        好处2: 模块之间就像搭建积木即可,又相互配合。 我想支持web也是非常轻松。

        好处3: 这样子再去整合Mybatis、或者其它的一些MQ、ES之类的中间件,就太简单了。

pom.xml   // 项目中使用了lettuce,这里作为演示

       <dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><!--(起码1.2.48以上)因为这个版本一下存在漏洞--><version>1.2.48</version></dependency>

1.Application.java

package com.example.springbootgame.application;import org.springframework.context.ApplicationContext;public class Application {private static ApplicationContext applicationContext;public static ApplicationContext getApplicationContext() {return applicationContext;}public static void setApplicationContext(ApplicationContext applicationContext) {Application.applicationContext = applicationContext;}public static <T> T getBean(Class<T> requiredType) {if (applicationContext == null) {return null;}return applicationContext.getBean(requiredType);}}

2.RedisConfig.java // 使用Configuration引入一些自定义的Bean

package com.example.springbootgame.config;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.sync.RedisCommands;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.time.Duration;
import java.time.temporal.ChronoUnit;@Configuration
public class RedisConfig {@Beanpublic GameRedis getGameRedis() {RedisURI redisURI = RedisURI.builder().withHost("localhost").withPort(6379).withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient redisClient = RedisClient.create(redisURI);return new GameRedis(redisClient.connect().sync());}
}

3.GameRedis.java // 包装器模式。包装出自己的访问接口

package com.example.springbootgame.config;import io.lettuce.core.api.sync.RedisCommands;public class GameRedis {private RedisCommands redisCommands;public GameRedis(RedisCommands redisCommands) {this.redisCommands = redisCommands;}public <K, V> V get(K k) {return (V) redisCommands.get(k);}public <K, V> void set(K k, V v) {redisCommands.set(k, v);}
}

4.LoginHandler.java

package com.example.springbootgame.handler;import com.alibaba.fastjson.JSON;
import com.example.springbootgame.config.GameRedis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import java.util.HashMap;
import java.util.Map;@Controller
public class LoginHandler {@AutowiredGameRedis gameRedis;/*** 玩家登录*/public void onCSLogin() {// 简单类型gameRedis.set("123", "abc");String v = gameRedis.get("123");System.out.println(v);// 复杂类型Data data = new Data();data.map.put("k", 6666);gameRedis.set("obj", JSON.toJSONString(data));Data obj = JSON.parseObject(gameRedis.get("obj"), Data.class);System.out.println(obj);}private static class Data {public int num = 1;public Map<String, Integer> map = new HashMap<>();@Overridepublic String toString() {return "Data{" +"num=" + num +", map=" + map +'}';}}
}

5.GameServer.java

package com.example.springbootgame;import com.example.springbootgame.application.Application;
import com.example.springbootgame.handler.LoginHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@SpringBootApplication
@Slf4j
public class GameServer {public static void registerShutdownHook() {Runtime.getRuntime().addShutdownHook(new Thread(() -> {log.info("gs shutdown in {}", Thread.currentThread().getName());// 测试bean的获取LoginHandler loginHandler = Application.getBean(LoginHandler.class);loginHandler.onCSLogin();// 关闭Spring容器ApplicationContext applicationContext = Application.getApplicationContext();if (applicationContext != null) {ConfigurableApplicationContext cac = (ConfigurableApplicationContext) applicationContext;cac.close();}}, "ShutdownHook-GameServer-Thread"));}public static void main(String[] args) {registerShutdownHook();// 启动Spring容器ApplicationContext applicationContext = SpringApplication.run(GameServer.class, args);Application.setApplicationContext(applicationContext);// 初始化各个模块,如:进行handler的扫描// 阻塞关服try {System.in.read();} catch (IOException e) {log.error("exception", e);}}}
  .   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::               (v2.7.17)2023-11-18 20:56:48.393  INFO 7056 --- [           main] com.example.springbootgame.GameServer    : Starting GameServer using Java 11.0.11 on DESKTOP-JTMBOEI with PID 7056 (D:\2_test_java\SpringBootGame\target\classes started by Administrator in D:\2_test_java\SpringBootGame)
2023-11-18 20:56:48.397  INFO 7056 --- [           main] com.example.springbootgame.GameServer    : No active profile set, falling back to 1 default profile: "default"
2023-11-18 20:56:48.960  INFO 7056 --- [           main] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2023-11-18 20:56:48.961  INFO 7056 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
2023-11-18 20:56:49.492  INFO 7056 --- [           main] com.example.springbootgame.GameServer    : Started GameServer in 1.512 seconds (JVM running for 2.701)
1
2023-11-18 20:56:50.723  INFO 7056 --- [meServer-Thread] com.example.springbootgame.GameServer    : gs shutdown in ShutdownHook-GameServer-Thread
abc
Data{num=1, map={k=6666}}

相关文章:

使用SpringBoot进行游戏服务器开发

背景&#xff1a; 之前一直只考虑用JavaSe进行游戏服务器开发&#xff0c;目前项目使用了Spring&#xff0c;发现还是非常好的&#xff0c;好处如下: 好处1:依赖注入非常方便&#xff0c;我们只使用Spring最基本的功能即可&#xff0c;这样子就算是有一些模块不使用Spring管理…...

数据结构——树状数组

文章目录 前言问题引入问题分析树状数组lowbit树状数组特性初始化一个树状数组更新操作前缀和计算区间查询 总结 前言 原题的连接 最近刷leetcode的每日一题的时候&#xff0c;遇到了一个区间查询的问题&#xff0c;使用了一种特殊的数据结构树状数组&#xff0c;学习完之后我…...

Untiy 使用RotateAround()方法实现物体围绕某个点或者某个物体旋转

Untiy 实现物体围绕指定点或者某个物体旋转&#xff0c;可使用RotateAround()方法。 语法&#xff1a; public void RotateAround(Vector3 point, Vector3 axis, float angle); 其中&#xff0c;point:旋转中心点位置&#xff1b; axis:要围绕的轴&#xff0c;如x,y,z angel…...

图像分类(五) 全面解读复现ResNet

解读 Abstract—摘要 翻译 更深的神经网络往往更难以训练&#xff0c;我们在此提出一个残差学习的框架&#xff0c;以减轻网络的训练负担&#xff0c;这是个比以往的网络要深的多的网络。我们明确地将层作为输入学习残差函数&#xff0c;而不是学习未知的函数。我们提供了非…...

使用html2canvas转换table为图片时合并单元格rowspan失效,无边框显示问题解决(React实现)

最近使用 html2canvas导出Table表单为图片&#xff0c;但是转换出的图片被合并的单元格没有显示边框 查了原因是因为我为tr设置了背景色&#xff0c;然后td设置了rowspan&#xff0c;设置了rowspan的单元格就会出现边框不显示的问题。 解决方法就是取消tr的背景色&#xff0c;然…...

pandas教程:Time Series Basics 时间序列基础

文章目录 11.2 Time Series Basics&#xff08;时间序列基础&#xff09;1 Indexing, Selection, Subsetting&#xff08;索引&#xff0c;选择&#xff0c;取子集&#xff09;2 Time Series with Duplicate Indices&#xff08;重复索引的时间序列&#xff09; 11.2 Time Seri…...

【C++初阶】STL详解(四)vector的模拟实现

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…...

Zookeeper学习笔记(2)—— Zookeeper API简单操作

前置知识&#xff1a;Zookeeper学习笔记&#xff08;1&#xff09;—— 基础知识-CSDN博客 Zookeeper集群搭建部分 前提&#xff1a;保证zookeeper集群处于启动状态 环境搭建 依赖配置 <dependencies><dependency><groupId>junit</groupId><arti…...

YOLOv8-Seg改进:Backbone改进 |Next-ViT堆栈NCB和NTB 构建先进的CNN-Transformer混合架构

🚀🚀🚀本文改进:Next-ViT堆栈NCB和NTB 构建先进的CNN-Transformer混合架构,包括nextvit_small, nextvit_base, nextvit_large,相比较yolov8-seg各个版本如下: layersparametersgradientsGFLOPsnextvit_small61033841075...

DocCMS keyword SQL注入漏洞复现 [附POC]

文章目录 DocCMS keyword SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 DocCMS keyword SQL注入漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测…...

利用(Transfer Learning)迁移学习在IMDB数据上训练一个文本分类模型

1. 背景 有些场景下&#xff0c;开始的时候数据量很小&#xff0c;如果我们用一个几千条数据训练一个全新的深度机器学习的文本分类模型&#xff0c;效果不会很好。这个时候你有两种选择&#xff0c;1.用传统的机器学习训练&#xff0c;2.利用迁移学习在一个预训练的模型上训练…...

pom.xml格式化快捷键

在软件开发和编程领域&#xff0c;"格式化"通常指的是将代码按照一定的规范和风格进行排列&#xff0c;以提高代码的可读性和维护性。格式化代码有助于使代码结构清晰、统一&#xff0c;并符合特定的编码规范。 格式化可以包括以下方面&#xff1a; 缩进&#xff1a…...

【短文】【踩坑】可以在Qt Designer给QTableWidge添加右键菜单吗?

2023年11月18日&#xff0c;周六上午 今天早上在网上找了好久都没找到教怎么在Qt Designer给QTableWidge添加右键菜单的文章 答案是&#xff1a;不可以 在Qt Designer中无法直接为QTableWidget添加右键菜单。 Qt Designer主要用于创建界面布局和设计&#xff0c;无法直接添加…...

Git常用配置

git log 美化输出 全局配置参数 git config --global alias.lm "log --no-merges --color --dateformat:%Y-%m-%d %H:%M:%S --authorghost --prettyformat:%Cred%h%Creset - %Cgreen(%cd)%C(yellow)%d%Cblue %s %C(bold blue)<%an>%Creset --abbrev-commit"…...

力扣每日一题-数位和相等数对的最大和-2023.11.18

力扣每日一题&#xff1a;数位和相等数对的最大和 开篇 这道每日一题还是挺需要思考的&#xff0c;我绕晕了好久&#xff0c;根据题解的提示才写出来。 题目链接:2342.数位和相等数对的最大和 题目描述 代码思路 1.创建一个数组存储每个数位的数的最大值&#xff0c;创建一…...

【win32_001】win32命名规、缩写、窗口

整数类型 bool类型 使用注意&#xff1a; 一般bool 的false0&#xff1b;true1 | 2 | …|n false是为0&#xff0c;true是非零 不建议这样用&#xff1a; if (result TRUE) // Wrong! 因为result不一定只返回1&#xff08;true&#xff09;&#xff0c;当返回2时&#xff0c…...

机器学习第8天:SVM分类

文章目录 机器学习专栏 介绍 特征缩放 示例代码 硬间隔与软间隔分类 主要代码 代码解释 非线性SVM分类 结语 机器学习专栏 机器学习_Nowl的博客-CSDN博客 介绍 作用&#xff1a;判别种类 原理&#xff1a;找出一个决策边界&#xff0c;判断数据所处区域来识别种类 简单…...

AI工具合集

网站&#xff1a;未来百科 | 为发现全球优质AI工具产品而生 (6aiq.com) 如今&#xff0c;AI技术涉及到了很多领域&#xff0c;比如去水印、一键抠图、图像处理、AI图像生成等等。站长之家之前也分享过一些&#xff0c;但是在网上要搜索找到它们还是费一些功夫。 今天发现了一…...

代码随想录算法训练营Day 54 || 392.判断子序列、115.不同的子序列

392.判断子序列 力扣题目链接(opens new window) 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;&quo…...

C 语言 gets()和puts()

C 语言 gets()和puts() gets()和puts()在头文件stdio.h中声明。这两个函数用于字符串的输入/输出操作。 C gets()函数 gets()函数使用户可以输入一些字符&#xff0c;然后按Enter键。 用户输入的所有字符都存储在字符数组中。 空字符将添加到数组以使其成为字符串。 gets()允…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

9-Oracle 23 ai Vector Search 特性 知识准备

很多小伙伴是不是参加了 免费认证课程&#xff08;限时至2025/5/15&#xff09; Oracle AI Vector Search 1Z0-184-25考试&#xff0c;都顺利拿到certified了没。 各行各业的AI 大模型的到来&#xff0c;传统的数据库中的SQL还能不能打&#xff0c;结构化和非结构的话数据如何和…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...