zoukankan      html  css  js  c++  java
  • Groovy热更新Java实践

    之前在写Groovy动态添加方法和属性及Spock单测文章的时候,我还没意识到metaclass的神奇之处,直到有一天我突然想要不经过构建过程直接更新功能,也就是传说中的热更新。

    之前学过arthas的时候写过arthas命令redefine实现Java热更新的文章,之前看笨马在MTSC大会演示的功能差不多,不过是都是通过命令行手动触发的。如果通过服务调用命令,实在不是最优之选。

    然后我就想到了Groovy的metaclass,就想到了通过groovy.lang.GroovyShell执行上传的Groovy脚本,然后就可以达到一定程度的动态更新的需求。

    说干就干,先写个正常版本的验证。

    功能验证

    我先创建一个类,然后定义一个对象方法,简单输出一个数字。然后在main方法中创建两个对象,分别调用各自的test()方法,这中间通过metaClass重新实现test()方法,输出FunTester

    package com.funtest.groovytest
    
    import com.funtester.frame.SourceCode
    
    class HotUpdate extends SourceCode {
    
        public static void main(String[] args) {
            def update = new HotUpdate()
            update.test()
            HotUpdate.metaClass.test = {output("FunTester")}
            def update2 = new HotUpdate()
            update2.test()
    
        }
    
        public void test() {
            output(123)
        }
    
    }
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main 
      ###### #     #  #    # ####### ######  #####  ####### ######  #####  
      #      #     #  ##   #    #    #       #   #     #    #       #    # 
      #      #     #  # #  #    #    #       #         #    #       #    # 
      ####   #     #  # #  #    #    ####    #####     #    ####    #####  
      #      #     #  #  # #    #    #            #    #    #       #   #   
      #      #     #  #   ##    #    #       #    #    #    #       #    #  
      #       #####   #    #    #    ######  #####     #    ######  #     # 
    
    INFO-> main 123
    INFO-> main FunTester
    
    Process finished with exit code 0
    
    

    脚本实现

    经过功能验证,路已经通了。现在就开始编写脚本,脚本内容就是把metaClass重新实现test()方法的功能脚本化:

    import com.funtest.groovytest.HotUpdate
    import com.funtester.frame.Output
    HotUpdate.metaClass.test = {Output.output(\"FunTester\")}
    

    接下来,我通过groovy.lang.GroovyShell模拟服务器收到请求脚本(String类型参数)之后的功能。最后完整的代码就是:

    
    import com.funtester.frame.SourceCode
    import com.funtester.frame.execute.ExecuteGroovy
    
    class HotUpdate extends SourceCode {
    
        public static void main(String[] args) {
            def update = new HotUpdate()
            update.test()
            ExecuteGroovy.executeScript("import com.funtest.groovytest.HotUpdate\n" +
                    "import com.funtester.frame.Output \n" +
                    "\n" +
                    "HotUpdate.metaClass.test = {Output.output(\"FunTester\")}")
            def update2 = new HotUpdate()
            update2.test()
        }
    
        public void test() {
            output(123)
        }
    
    }
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main 
      ###### #     #  #    # ####### ######  #####  ####### ######  #####  
      #      #     #  ##   #    #    #       #   #     #    #       #    # 
      #      #     #  # #  #    #    #       #         #    #       #    # 
      ####   #     #  # #  #    #    ####    #####     #    ####    #####  
      #      #     #  #  # #    #    #            #    #    #       #   #   
      #      #     #  #   ##    #    #       #    #    #    #       #    #  
      #       #####   #    #    #    ######  #####     #    ######  #     # 
    
    INFO-> main 123
    INFO-> main FunTester
    
    Process finished with exit code 0
    
    

    完美实现,中间在拷贝脚本的时候遇到一些问题,就是Intellij会自动把一些字符当做转义字符来处理,导致执行的脚本和实际脚本有了差异导致失败,这里建议大家尽量避免使用这种直接粘贴复制字符串的方式,转而使用上传脚本文件或者使用ngrinder的方案,将脚本存放在可访问的Git仓库中。

    欢迎关注FunTester,Have Fun ~ Tester !

  • 相关阅读:
    vue-cli 3.x 配置多环境
    阿里云安装nodejs
    使用vuex实现父组件调用子组件方法
    关于图片预览使用base64在chrome上的性能问题解决方法
    手机开发遇到的若干坑(持续更新)
    java--03--cglib代理
    java--02--动态代理
    java--01--静态代理
    SocketIO---Netty--HelloWorld
    SocketIO---bio2---带线程池处理任务
  • 原文地址:https://www.cnblogs.com/FunTester/p/15628025.html
Copyright © 2011-2022 走看看