美文网首页
让Java代码动态运行

让Java代码动态运行

作者: 空山雪林 | 来源:发表于2018-12-29 14:51 被阅读0次

    背景

    Java是编译型语言,它不能向JavaScript一样被动态执行,但有时我们却不得不让Java代码能动态运行的能力,以便我们无需重启容器就可以达到动态发布服务的能力,比如我们要做一个爬虫解析程序,我们希望可以在平台上动态创建Java爬虫程序,但提交到平台后,代码会被自动编译成class文件然后注入到平台里,让爬虫运行起来,在比如API云平台里,我们希望有动态创建API的能力,能让Java代码通过平台上传后,相关的API接口能被自动创建而无需重启Web容器,那么我们该怎么做呢?

    动态API的设计思路

    1. 利用com.sun.tools.javac.api.JavacTool提供的工具类编译Java源文件;
    2. 命令行添加-encoding,-classpath,-parameters等必要参数信息,classpath载入平台可以提供jar上传,pom文件等;
    3. 成功编译成class文件后,利用DynamicClassLoader
    4. 需要开放的api函数做个统一的java注解,如@Api,将全部带有这个缓存的方法到一个Map中,Key可以是类名+方法名,也可以再使用一个注解定义自定义名字,以便后续作为restful api的uri使用,如TestController/method2
    5. 定义一个Web Filter,拦截如/api/打头的URI,根据规则解析定位到执行哪个方法哪个类,将函数的执行结果返回为restful api接口即可。

    动态定时任务的实现

    为了精简代码,我们以实现动态Job为例,讲解代码层面上的实现,同动态API设计思路类似,首先我们应该加载用户自己上传的依赖libs,代码如下:

    // 初始化Jar环境
    JarService.init();
            
    //举个例子,加载第三方依赖包
    String deps = "<dependency>\r\n" + 
                "     <groupId>com.squareup.okhttp3</groupId>\r\n" + 
                "     <artifactId>benchmarks</artifactId>\r\n" + 
                "     <version>3.12.0</version>\r\n" + 
                "   </dependency>";
    JarService.savePom(mavenDeps(deps));
    

    启动定时任务管理器,其中RunTaskJob类用来从运行Job队列中获取任务执行:

    ThreadManager.stopScheduler();
    ThreadManager.startScheduler();
    new Thread(new RunTaskJob()).start();
    

    接着就可以编写Java代码来向ThreadManager动态添加执行Java代码了:

    String code = "package com.sumslack.compile.java.test;\r\n" + 
                    "\r\n" + 
                    "import com.sumslack.compile.dyna.java.anno.DefaultExecute;\r\n" + 
                    "import java.util.Date;\r\n" + 
                    "\r\n" + 
                    "public class MyTestRun {\r\n" + 
                    "\r\n" + 
                    "   @DefaultExecute\r\n" + 
                    "   public void defaultTest() {\r\n" + 
                    "       System.out.println(new Date() + \" ===> test job\");\r\n" + 
                    "   }\r\n" + 
                    "}";
    Task task = new Task();
    task.setId(1L);
    task.setName("testTask");
    task.setStatus(1);
    task.setCode(code);
    task.setScheduleStr("*/4 * * * * ?");
    if(new JavaRunner(task).check()) {
        new JavaRunner(task).compile();
        RunTaskJob.tasks.put(task.getName(), task);
        ThreadManager.add(task);
    }
    

    代码运行后,我们可以看到程序按照定义的cron表达式每隔4s执行一次Job,如下图:


    image.png

    以上,就达到了在平台上通过编写Java代码增加Job的能力,如果你的Job有用到第三方jar,只需要JarService.savePom一下就可以了,动态执行Java在很多应用场合会被使用到,如果你对这部分代码感兴趣,可以在https://github.com/kongshanxuelin/sumscope_nb_it/tree/master/com.sumslack.compile.dyna中获取完整本文的代码

    注:代码由jcoder上精简而成

    相关文章

      网友评论

          本文标题:让Java代码动态运行

          本文链接:https://www.haomeiwen.com/subject/zdnykqtx.html