java netty 分布式游戏服务器框架 ioGame 17.1.27
#27
业务框架与网络通信框架解耦
新增 ChannelContext 通信通道接口,用于对 bolt AsyncContext、netty Channel 的包装,这样可以使得业务框架与网络通信框架解耦,为将来 ioGame 实现绳量级架构的使用做准备。
移除 FlowAttr.asyncContext 动态属性,由 FlowAttr.channelContext 代替。
业务框架模块移除网络相关的依赖 bolt、netty 等。
#28
游戏对外服 netty 编排业务钩子接口
新增 ChannelPipelineHook netty 业务编排的处理器钩子接口,用于游戏对外服。
ExternalServerBuilder 新增 channelPipelineHook 属性 ,用于自定义 netty 业务编排的处理器设置。
废弃标记 ExternalServerBuilder.channelHandlerProcessors 属性及其相关地方为过期,由 ChannelPipelineHook 来代替,使用示例如下。
public class ExternalServerBuilderApplication {
public static void main(String[] args) {
// netty ChannelHandler 编排
var myChannelPipelineHook = new ChannelPipelineHook() {
@Override
public void initChannelPipeline(ChannelPipeline pipeline) {
pipeline.addLast("ExternalBizHandler", new ExternalBizHandler());
// pipeline.addFirst("ssl", ssl)
}
};
// 游戏对外服构建器
ExternalServerBuilder builder = ExternalServer.newBuilder(10100);
builder.channelPipelineHook(myChannelPipelineHook);
}
}
通常情况下,这样的编排方式也会更加清晰,因为代码统一在这里做编排了。开发者在自定义业务编排时,可以通过这个钩子接口,比如添加一个 SSL。
注意事项:在调用 hook 前,会经过 ExternalChannelInitializerCallback.initChannelPipeline(SocketChannel) ,
ExternalChannelInitializerCallback 接口的实现类有
- ExternalChannelInitializerCallbackWebsocket
- ExternalChannelInitializerCallbackTcp
这些实现类中,会给 ChannelPipeline 添加上一些默认的处理器,通常是编解码相关的。
在处理 action 时,我们可以通过 FlowContext.userId 可以很方便得到当前用户(玩家)id。
如果开发者想在处理 action 时,携带上一些自定义的信息时,可以通过元附加信息特性来完成。比如保存当前玩家的英雄角色 id,或者玩家的昵称,又或者是你的项目的 userId 是 string 或其他类型则可以通过元信息这一特性来兼容。
简单的说,就是你想在 FlowContext 中获取一些用户(玩家)特有的信息数据时,可以通过这个特性来实现。
// 自定义一个元信息类,实现 Attachment 元附加信息接口
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class MyAttachment implements Attachment {
@Getter
long userId;
String nickname;
}
@ActionController(1)
public class DemoAction {
@ActionMethod(1)
public void attachment(FlowContext flowContext) {
// 创建自定义的元附加信息对象
MyAttachment myAttachment = new MyAttachment();
myAttachment.userId = flowContext.getUserId();
myAttachment.nickname = "英雄无敌3";
// 设置元信息 ----- 关键代码
ExternalCommunicationKit.setAttachment(myAttachment);
}
@ActionMethod(2)
public MyAttachment printAttachment(FlowContext flowContext) {
// 得到元信息,这个是在上面的方法中设置的元信息对象
var attachment = flowContext.getAttachment(MyAttachment.class);
return attachment;
}
}
通过这个示例可以看出,元信息的设置与获取是简单的。
甚至你还可以配合自定义 FolwContext 特性 ,对这个扩展做更符合项目的定制,如下
// 自定义一个元信息类,实现 Attachment 元附加信息接口
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class MyAttachment implements Attachment {
@Getter
long userId;
String nickname;
}
public class MyFlowContext extends FlowContext {
public String getNickname() {
var attachment = this.getAttachment(MyAttachment.class);
return attachment.nickname;
}
}
@ActionController(1)
public class DemoAction {
@ActionMethod(1)
public void attachment(MyFlowContext flowContext) {
// 创建自定义的元附加信息对象
MyAttachment myAttachment = new MyAttachment();
myAttachment.userId = flowContext.getUserId();
myAttachment.nickname = "英雄无敌3";
// 设置元信息 ----- 关键代码
ExternalCommunicationKit.setAttachment(myAttachment);
}
@ActionMethod(3)
public void printAttachment(MyFlowContext flowContext) {
var nickname = flowContext.getNickname();
System.out.println(nickname);
}
}
其他优化
命令解析器与源码文档逻辑分离。
优化命令对象,减少 action 类的实例化对象