Organizations

56 results for Java
  • 最开始 pekko 本身是起源于 akka, 因为 akka 转为商业许可而演变出来的开源替代版本, 两者在早期的 abi 基本上是类似, 而后续 akka 追加不少商业的功能支持. akka搭建服务需要买授权码, 为了避免商业纠纷问题推荐采用 pekko 学习 两者在使用中没什么差异, 更多差异来源于本身的 类型系统 差别: actor 和 actor-typed 最明显的就是 pekko 当中的声明 actor 不同的抽象定义: // 弱类型定义类 class Worker extends AbstractActor{ // do something } // 强类型泛型类 class Worker extends AbstractBehavior<T>{ // do something } AbstractActor: 基于弱类型的Actor抽象. 允许接收任何类型的消息, 在处理消息时需要通过模式匹配或其他方式来判断消息的具体类型并进行相应的处理. 这种方式在编译时无法对消息类型进行检查, 可能导致运行时出现类型不匹配的错误. AbstractBehavior<T>:基于强类型的Actor抽象. 它通过 类型参数<T> 明确指定了 Actor 所能接收的消息类型并在编译时会进行严格的类型检查, 确保只有正确类型的消息才能发送给 Actor 从而提高了代码的稳定性和可维护性. AbstractActor 方式内部本身采用 Object 装载传输消息, 在编译的时候没办法做类型检查(毕竟最后数据都用 Object 包装), 现在在网上大部分教程都是以这种方式构建 actor.
    Java Created Mon, 09 Jun 2025 14:18:02 +0800
  • 之前已经展示封装成功能 Actor, 可以看到我们封装类和 skynet 类似, 在官方 vert-x 文档可以看到比较简单的 WebSocket 集成设置: import io.vertx.core.Vertx; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.WebSocket; public class WebSocketServerExample { public static void main(String[] args) { // 创建Vertx实例 Vertx vertx = Vertx.vertx(); // 创建Http服务器选项 HttpServerOptions options = new HttpServerOptions() .setPort(8080); // 创建Http服务器 HttpServer server = vertx.createHttpServer(options); // 监听HTTP请求并升级为WebSocket连接 server.webSocketHandler(webSocket -> { System.out.println("WebSocket连接已建立"); // 处理接收到的WebSocket消息 webSocket.handler(buffer -> { String message = buffer.toString(); System.out.println("收到消息: " + message); // 发送响应消息 webSocket.writeTextMessage("你发送的消息是: " + message); }); // 处理WebSocket连接关闭事件 webSocket.
    VertX Java Created Sun, 01 Jun 2025 18:29:00 +0800
  • 如果常使用 Spring 就会接触到大量内部 IoC(控制反转) 容器, 比较常用 @Component 就是全局实例化能被追踪. IoC 涵盖以下概念: 控制反转: 抛弃传统开发手动 new 实例化而让容器来帮助全局实例化管理 依赖注入: 通过 构造方法(Spring-@Autowired,Java-@Resource)/Setter(写入器-@Bean)/XML等配置 将实例注入引用 这样的好处就是把实例化和引用管理移交给到容器统一管理从而能够专注业务, 这里以 spring 为例子说明: // 定义一个服务接口 public interface HelloService { void sayHello(); } // 实现服务接口 public class HelloServiceImpl implements HelloService { public void sayHello() { System.out.println("Hello, Spring IoC!"); } } // 配置文件(applicationContext.xml) <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="com.example.HelloServiceImpl"/> </beans> // 使用IoC容器 public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.
    Java Created Thu, 08 May 2025 14:59:27 +0800
  • 虽然 Spring 全家桶直接编写 application.yml 就可以配置日志等级, 但是在后续脱离 spring 就需要另外采用其他日志配置, 一般就是采用 logback 来处理. 需要注意每个版本 logback 或者日志实现可能变动很大, 所以在升级或者更换实现的时候要留意 这里先引入依赖第三方需求库: <dependencies> <!-- logback配置: 1.5.18版本 --> <!-- 默认会引入: slf4j-api --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.5.18</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.5.18</version> </dependency> </dependencies> 之后就是在 src/main/resources 创建 logback.xml 配置, 而外部 jar 包启动加载配置稳健这可以采用以下启动配置: # 启动的时候加载 logback.xml 配置 java -jar -Dlogging.config="/etc/fusion/websocket-logback.xml" test.jar 而其中需要知道日志等级涵盖有: OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE, 这里想设计个最基础的配置: <?xml version="1.0" encoding="UTF-8"?> <!-- scan: 当此属性设置为true时, 配置文件如果发生改变将会被重新加载, 默认值为true --> <!-- scanPeriod: 设置监测配置文件是否有修改的时间间隔, 如果没有给出时间单位默认单位是毫秒; 当scan为true时, 此属性生效. 默认的时间间隔为1分钟.
    Java Created Wed, 07 May 2025 22:21:20 +0800
  • 最近需要部署搭建个 WebSocket 的游戏网关服务端, 考虑之后从 Java 之中选取设计方案; 而这里首先排除 Spring 全家桶系列, 因为内部集成太过冗余且对底层操作也比较麻烦, 最后敲定方案采用仅仅对网络工具方法抽象的 Vert-X. 这里 Actor 最开始考虑 akka, 但是目前最新版本已经从开源协议转为商业协议, 为了后续规避潜在的商业纠纷最后采用同源的开源替代 pekko. 而消息交换协议, 最开始在单纯二进制和 protbuf 之间考虑, 主要问题是 protobuf 协议生成的类文件对于项目侵入太严重; 所以考虑在三之后选择性能更好且通用型更强的 msgpack. 建议对 WebSocket 协议规范 rfc6455 进行学习, 因为相对于 TCP 来说底层已经做好 帧(Frame) 概念处理, 所以直接只用处理消息接收和推送即可. 对于 WebSocket 来说基本上传递数据格式已经内置数据类型: 0x1: 文本内容 0x2: 二进制内容 0x8: 关闭连接 0x9: Ping 0xA: Pong 这主要是区分好消息格式发送什么, 用来推送给 Actor 内部消息来处理不同的业务逻辑. 另外需要设计好 actor 拓扑图, 需要对 actor 功能做基本设计分布: [ActorSystem,最基础的系统] | | [Supervisor,核心管理器负责监控所有 Worker] --- [Worker:WebSocket,网络层负责协调客户端和Actor关联,同时负责动态会话创建] | | | | | |- [Worker * N:(UUID) Session, 每个会话都动态创建 actor] | | | |- [会话Actor是不断动态创建的].
    VertX Java Created Wed, 07 May 2025 13:51:05 +0800
  • 对于日常 Web 应用来说 Spring 全家桶已经足够用, 但是涉及到某些底层操作(TCP|UDP|WebSocket)的时候就感觉冗余且捉襟见肘. Spring 封装过头导致及其冗余, 很多组件其实没有那么必要引入, 所以需要重新选择技术栈; Spring 作为框架太复杂在网上检索到 VertX 来做工具集: Spring:作为 框架(Framework) 集成大量日常通用工具并且屏蔽底层封装高级接口 VertX: 内部采用 netty 做底层将对应方法简略封装, 所以更像是 工具集(Utilities) 如果需要编写网关层, 推荐采用该方案, 原生 netty 虽然也可以但是缺失很多关键部件 对于底层网络基础来说 VertX 就更加符合需求, 所以在考虑之后决定引入: <dependencies> <!-- 最基础的核心底层, 如果功能单一基本上只需要该第三方库就行了 --> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-core</artifactId> <version>4.5.14</version> </dependency> <!-- Web功能服务 --> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-web</artifactId> <version>4.5.14</version> </dependency> <!-- MYSQL数据库客户端,支持池处理 --> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-mysql-client</artifactId> <version>4.5.14</version> </dependency> <!-- JUnit 测试框架参照: https://vertx.io/docs/vertx-junit5/java/ --> </dependencies> 建议配合 JCommander 编写成命令行工具, 抛弃原来集成 Spring 臃肿的组件
    架构 Java Created Sat, 03 May 2025 22:41:05 +0800
  • 在日常当中对于常规使用 Web 项目都会集成 SpringBoot 工具, 一般来说直接按照以下方式启动就行: # 启动 Jar 并携带启动配置文件 java -jar package.jar -Dspring.config.location=./application.yml 实际上其他简单和非Web应用并不需要集成这么重量级框架, 所以应该回归到传统附带启动参数的方法, 采用第三方库 JCommander 就能直接编写简单高效的命令行启动工具. 建议: 命令行最好全部采用英语而不要用中文emoji等特殊字符说明, 有的环境会因为缺少字符集乱码(英语最通用所以基本默认集成) 按照官方需要引入第三方库: <!-- JCommander 第三方库 --> <dependency> <groupId>org.jcommander</groupId> <artifactId>jcommander</artifactId> <version>2.0</version> </dependency> 这里推荐还需要设置打包工具, 让其打包的时候指定 main 入口类, 避免启动的时候无法找到入口类: <!-- Maven打包配置 --> <build> <plugins> <!-- 编译打包配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <source>17</source> <target>17</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- Jar打包功能配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.4.2</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <!-- 这里就是默认启动的入口类文件 com.fusion.game.FusionHttpApplication.java --> <mainClass>com.
    部署 Java Created Sat, 03 May 2025 15:44:03 +0800
  • 作为单机 Actor 结构目前已经实现简单的转发功能, 但是需要注意对于客户端消息来说有以下区分: 请求(request): 客户端主动推送给服务端消息包 响应(response): 服务端主动推送给客户端消息包 需要区分 长连接 和 短连接 区别, 短连接(HTTP) 要求从发起到响应必须双向(请求必须要带响应); 而长连接(TCP|UDP) 是非双向, 也就是可能只有请求而没有响应或者干脆只有响应. 我们编写的简单 Actor 虽然完成基本将客户端消息请求功能, 但是目前没有合适的响应功能, 而没有合适响应功能也就没办法实现我们之前 服务端心跳包 需求. 但是这时候不要先急着去实现, 而是要回头思考下: 为什么消息格式能够被正确转发? 消息传递 从 ActorRef<T> 得出这里面推送的消息结构是泛型, 也就是可能本身也就是 Object 对象, 而 createReceive 的回调就更加明显展示消息转化流程: public <M extends T> ReceiveBuilder<T> onMessage(final Class<M> type, final Function<M, Behavior<T>> handler) { OptionVal.Some var10000 = org.apache.pekko.util.OptionVal.Some..MODULE$; org.apache.pekko.util.OptionVal..MODULE$.None(); // 关键的转化流程, 实际上就是按照传入的动态类型转化写入匹配路由 Case var3 = new Case(type, (Predicate) null, handler); this.messageHandlers_$eq((List) this.messageHandlers().$plus$colon(var3)); return this; } 这个方法往下就能看到 class Case<BT, MT> implements Product, Serializable 转化类, 其中关键内容方法已经展示出来了:
    Java Actor Created Sun, 20 Apr 2025 19:05:30 +0800
  • 之前已经创建好第一个属于我们的 Actor 系统, 但是内部完全没有任何交互, 现在就是开始设计业务来模拟日常业务, 这里需要定义设计个 世界boss 功能. 世界boos 每分钟都会刷新血量 websocket 每10s都会推送客户端心跳包 每个新连接 websocket 都支持攻击1次, 随机返回攻击数值并扣除血量 如果结算时间到就会给在线会话推送攻击的扣除最高血量 这里就是简单的初步游戏业务功能, 这里需要设计网络运输网关层组件: <!-- 第三方依赖 --> <dependencies> <!-- 之前的其他组件 --> <!-- SpringWebSocket --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies> 之后就是改造 main 入口和配置全局属性: import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.socket.config.annotation.EnableWebSocket; /** * 游戏项目启动入口, 现在托管给 SpringBoot 来管理 * 默认启动WebSocket设置 */ @EnableWebSocket @SpringBootApplication public class FusionActorApplication { /** * 启动项目方法 * * @param args 启动方法 */ public static void main(String[] args) { SpringApplication.
    Java Actor Created Sat, 19 Apr 2025 18:53:00 +0800
  • 这里依赖以下第三方库组件来构建第一个游戏网关: lombok: 节约 GET|SET 开发流程 spring-boot: 基础依赖注入组件 logback: 更新版本日志组件, spring-boot 老版本需要覆盖避免漏洞 spring-boot-websocket: WebSocket 传输层 pekko: akka 的开源替代 actor 模型 jvm 语言其实选择比较, 按照个人喜好就行了: java: 老牌语言实现, 稳定性和兼容性最好 groovy: 动态脚本语言, 支持 jvm 的动态热更新 scala: 携带大量语法糖且高度抽象的实现编程语言语言 kotlin: JetBrains 官方直接支持, 开发效率很不错 实际上还是建议还是采用 Java 语言作为编程语言, 因为大部分商业游戏都是挂靠 Unity3d+C# 实现, 而 C# 大部分语法都是和 Java 近似, 所以有时候服务端+客户端有时候业务繁忙的时候客户互相帮忙编写. 另外还有 pekko 挂载 quickjs|lua 虚拟来做动态热更新, 这种方式也能兼容游戏客户端如果采用双端脚本的方案 在正式进入之前需要说明下服务器架构选择流程: # 1. 转发服务集群 客户端(TCP) ------| | | | ------- [(同进程) NettyTCP -> GatewaActor (startProxy) ] ------- AuthorityActor | | ----------------------------------- WorldActor | ----------------------------------- PlayerActor # 2.
    Java Actor Created Sat, 19 Apr 2025 11:53:29 +0800