一般来说,现在游戏服务器都实现了java代码热更新的机制,这样就可以不用重启服务器,在服务器运行的状态中修改一些Java代码,修改一些小Bug,这给我们带来了很好的方便,但是Java服务器热更新也有一些限制,比如不能添加新方法,不能修改原方法的签名(不能修改返回类型,不能原方法修改参数)等。但是有时候在不知不觉中就可能违反了这些限制,导致热更新失败。
    在服务器热更新对象的时候,一定要注意匿名类的热更新,它最容易引起方法参数不一致问题,导致热更新失败。即使强制替换了class文件,也会导致报错:java.lang.NoSuchMethodError
    下面我们来验证这个问题

    1. 首先创建一个抽象类,用这个抽象类创建匿名类使用

      1. /**
      2. * @author 王广帅
      3. * @date 2021年01月14日 12:10 上午
      4. */
      5. public abstract class AbstractInnerTest {
      6. public abstract void run();
      7. }
    2. 再创建一个类,在这个类中使用上面创建的抽象类创建匿名类使用

      1. /**
      2. * @author 王广帅
      3. * @date 2021年01月14日 12:04 上午
      4. */
      5. public class MyTest {
      6. public static void main(String[] args) {
      7. int a = 0;
      8. String b = "b";
      9. List<String> list = new ArrayList<>();
      10. executeTask(new AbstractInnerTest() {
      11. @Override
      12. public void run() {
      13. System.out.println(list);
      14. System.out.println(a);
      15. System.out.println(b);
      16. }
      17. });
      18. }
      19. public static void executeTask(AbstractInnerTest task) {
      20. task.run();
      21. }
      22. }
    3. 编译这两个类,可以获得三个class文件

    image.png

    1. 使用javap -c 命令查看MyTest$1.class的字节码指令

    image.png
    上面红框标记的地方就是这个匿名类在使用的时候(在new AbstractInnterTest)要调用的构造方法,可以看到这个构造方法的参数类型顺序是List , int , String

    1. 然后修改MyTest类中,在匿名类中参数使用的顺序

      1. /**
      2. * @author 王广帅
      3. * @date 2021年01月14日 12:04 上午
      4. */
      5. public class MyTest {
      6. public static void main(String[] args) {
      7. int a = 0;
      8. String b = "b";
      9. List<String> list = new ArrayList<>();
      10. executeTask(new AbstractInnerTest() {
      11. @Override
      12. public void run() {
      13. System.out.println(a);
      14. System.out.println(b);
      15. System.out.println(list);//调整一下参数使用顺序
      16. }
      17. });
      18. }
      19. public static void executeTask(AbstractInnerTest task) {
      20. task.run();
      21. }
      22. }
    2. 再重新编译之后,使用java -c 命令重新打开MyTest$1.class

    image.png
    可以看到,上面红框中标记的构造方法的参数类型顺序变成了 int , String ,List

    结论:这就相当于修改了方法的签名,在java的热更新机制中,是不支持修改方法签名热更新的,也不支持添加新的方法。所以,如果热更新的代码在匿名类之中,一定要注意匿名类中参数的使用顺序。


    文章中插入的公众号关注.png