对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,JVM给我们提供了一些接口,可以简单做一些热更新。修复一些小Bug而不用重启服务。

JVM可以给运行中的服务器绑定一个代理,在这个代理中可以拿到Instrumentation 这个类的实例,它可以让用户手动修改jvm中的class类,对它进行热更新,但是有一点,用于热更新的新类和老的类方法签名必须一样,即不能修改方法的名字,参数类型,还有修改声明的字段。只能修改方法体里面的代码。一般的小bug都是方法体内的逻辑漏洞,不会做很多大的修改,所以这种方式还是能满足我们的需要求的。

现在我们分三个项目:

1,GameServer 即我们正常的游戏服务器。

2,LoadAgent  这个是热更新的代理项目,热更新的操作就在这里面执行。

3,GameServerHotBoot    这个项目是用来把LoadAget代理和GameServer进行绑定的。

JDK代理的两种方式:

1.premain方式是Java SE5开始就提供的代理方式,但其必须在命令行指定代理jar,并且代理类必须在main方法前启动,它要求开发者在应用启动前就必须确认代理的处理逻辑和参数内容等等

2.agentmain方式是JavaSE6开始提供,它可以在应用程序的VM启动后再动态添加代理的方式

应用场景:

premain这种方式必须在jar包启动的时候进行指定,它是运行在项目的main方法之前的,即项目启动时:

java – javaagent:LoadAgent.jar -jar GameServer.Jar

但是正常的生产环境下,一般不会开启代理功能,但是在发生问题时,我们不希望停止应用就能够动态的去修改一些类的行为,以帮助排查问题,这在应用启动前是无法确定的。这时agentmain就可以做到了。所以我们采用agentmain这种方式。

1,LoadAgent实现

这个实现也比较简单,就像我们的程序入口有main方法一样,它需要一个agemtmain方法

public class GameServerAgent {

    public static void agentmain(String args, Instrumentation inst) throws Exception {

        System.out.println("agent 启动成功,开发重定义对象....");

        Class<?>[] allClass = inst.getAllLoadedClasses();
for (Class<?> c : allClass) {
if (c.getName().endsWith("TestHot")) {
String pathname = "config\\TestHot.class";
File file = new File(pathname);
try {
byte[] bytes = fileToBytes(file);
System.out.println("文件大小:" + bytes.length);
ClassDefinition classDefinition = new ClassDefinition(c, bytes);
inst.redefineClasses(classDefinition);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("转换代码。。。");
}
}
System.out.println("热更新成功...."); } public static byte[] fileToBytes(File file) throws IOException {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[in.available()];
in.read(bytes);
in.close();
return bytes;
}
}

对某个class的替换有两种方式

1,使用ClassFileTransformer

2,使用ClassDefinition

由于ClassDefinition比较方便,所以我们使用ClassDefinition对类进行更新。

项目源码地址:https://github.com/youxijishu/game-hot-update

热更新步骤:

1,打包LoadAgent

在使用LoadAgent的时候,需要在MANNIFEST.MF添加一些属性

Agent-Class: com.xinyue.hot.agent.GameServerAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true

这个在可以在打包的pom.xml中配置

 <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath> </manifest>
<manifestEntries>
<Agent-Class>
com.xinyue.hot.agent.GameServerAgent
</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>

然后使用mvn install命令即可,在target中找到生成的jar,LoadAgent-0.0.1-SNAPSHOT.jar,把它放到GameServer下的config目录下面,这里是测试,用的相对路径。

2,在GameServer中创建一个测试的类,叫TestHop.java,使用里面有一个输出方法,打印1,然后使用mvn install进行编译,在target/classes中找到这个类,把它也复制到GameServer的config路径下面。

3,把TestHop类中的输出修改为2,运行GameServer,这时会输出pid和2

4,把pid复制到GameServerHotUpdate的HotUpdateMain类中,当然,在实际应用中也可以通过args传进来。然后运行HotUpdateMain,等会儿就会输出结果

这时我们发现类的输出变化了,没有热更之前输出是的2,热更新之后,输出的是1.说明,热更新成功了。

项目源码地址:https://github.com/youxijishu/game-hot-update


QQ群交流:66728073,更多文章:http://www.coc88.com;公众号:

游戏服务器之Java热更新的更多相关文章

  1. spring boot热部署 -- 实现 后端java热更新 -- 详细操作 【idea 的 JRebel破解】

    1.前言 上一随笔写了如何使得spring boot热更新前端 ,但后端java部分无法热更新. 对于Java热更新,以前常使用  springloaded  ,但是缺点 和bug很多 无法实现真正意 ...

  2. (4/24) webpack3.x快速搭建本地服务和实现热更新

    写在前面: (1)为了防止版本兼容问题,此处的webpack版本与之前的一致为:webpack@3.6.0.同时这里我们安装的webpack-dev-server版本是2.9.7版本. (2)之前已经 ...

  3. Java 热更新 Groovy 实践及踩坑指南

    Groovy 是什么? Apache的Groovy是Java平台上设计的面向对象编程语言.这门动态语言拥有类似Python.Ruby和Smalltalk中的一些特性,可以作为Java平台的脚本语言使用 ...

  4. C#热血传奇游戏服务端再次开源更新

    2014年新春佳节即将到来,也算是送给大家的一份新年礼物.虽然这礼物貌似不给力啊哈哈.(没有用心啊 o(∩_∩)o 哈哈) 这次开源主要去掉上一次开源版本中大量指针代码,简化上手操作,并重构大部分代码 ...

  5. unity游戏热更新

    链接:https://pan.baidu.com/s/1ggWP0OF 第 1 章 : 热更新技术学习介绍 课时1:101-热更新技术学习介绍 11:55 什么是热更新? 举例来说 游戏上线后,玩家下 ...

  6. spring cloud --- 使用 actuator 热更新【刷新】单机配置文件

    1.前言 分布式微服务想要热更新配置文件,还需要 消息中间件 配合使用 ,一般使用 rabbitMQ 或 Kafka ,这里不解释 . 这篇随笔 只讲解 底层的 单机热更新配置文件 2.环境 spri ...

  7. lua转让C++书面DLL达到“热更新”

    原创作品,请注明出处转载CSDN:http://blog.csdn.net/relar/article/details/38084689 开发游戏server往往有"热更新"的需求 ...

  8. [Android教程] Cordova开发App入门(二)使用热更新插件

    前言 不知各位遇没遇到过,刚刚发布的应用,突然发现了一个隐藏极深的“碧油鸡(BUG)”,肿么办!肿么办!肿么办!如果被老板发现,一定会让程序员哥哥去“吃鸡”.但是想要修复这个“碧油鸡”,就必须要重新打 ...

  9. Unity热更新技术整理

    一.热更新学习介绍 1.什么是热更新 举例来说: 游戏上线后,玩家下载第一个版本(70M左右或者更大),在运营的过程中,如果需要更换UI显示,或者修改游戏的逻辑,这个时候,如果不使用热更新,就需要重新 ...

随机推荐

  1. Linux 开机启动顺序_005

    ***了解Linux开机启动顺序之前先了解一下Linux运行级别,通过inittab配置文件查看运行级别的定义: [root@oldboy ~]# cat /etc/inittab # Default ...

  2. python从XML里取数,遍历等

    #coding=utf-8 #通过minidom解析xml文件 import xml.dom.minidom as xmldom import os ''' XML文件读取 <?xml vers ...

  3. C# 鼠标移动Winform窗体内或者panel容器内的控件 显示虚线/实现虚线框来确定位置

    C# 鼠标移动WinForm窗体或者panel容器内的控件 移动虚线/实现虚线框来确定位置 1.用到的方法介绍 今天,根据领导指示指导移动容器内的控件,生成虚线框,使用 ControlPaint.Dr ...

  4. css背景图撑开盒子高度

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. ZooKeeper注册中心安装详细步骤(单节点)

    安装 Dubbo 注册中心 Dubbo 建议使用 Zookeeper 作为服务的注册中心. 注册中心服务器(192.168.3.71)配置,安装 Zookeeper: 1. 修改操作系统的/etc/h ...

  6. Java课程寒假之开发记账本软件(网页版)之三

    一.实现基础功能之一(查询)(补) 在上一篇中解释的不够详细,在本篇中补充一下指定日期查询,其实和查询没有什么区别,就是设置select下拉框来对于日期的起始与结束日期,然后就是一个简单的mysql语 ...

  7. 为 git设置代理

    普通设置 git config --global http.proxy 'socks5://127.0.0.1:1080'git config --global https.proxy 'socks5 ...

  8. Sring 类的例子

    public class ZongHe {     public static void main(String[] args) {     function1();            funct ...

  9. transform的兼容性写法浏览器 和 transition

    transform:rotate(7deg); -ms-transform:rotate(7deg); /* IE 9 */ -moz-transform:rotate(7deg); /* Firef ...

  10. PHP指定时间戳/日期加一天,一年,一周,一月

    PHP指定时间戳加上1天,1周,1月,一年其实是不需要用上什么函数的!指定时间戳本身就是数字整型,我们只需要再计算1天,1周它的秒数相加即可! 博主搜索php指定时间戳加一天一年,结果许多的文章给出来 ...