让Java代码动态运行

2018-12-29  本文已影响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上精简而成

上一篇 下一篇

猜你喜欢

热点阅读