天天看点

java 如何循环执行一个对象_写一个在线Java脚本执行器

在生产环境中,有时候我们想要快速执行一段代码,但是又不得不经历上线的痛苦(分情况哈,有时候这种痛苦是必须的)或者在某些场景中,不能重启避免破坏现场,那么有个在线脚本执行器就最好不过了。于是在工作之余,便写了这么一个

jrc 小工具

(当然市场上可能会有更好的选择,比如阿里巴巴的arthas,大家如果有更习惯的工具,也可以不参考我这个哈)

这个工具主要就是利用了java自带的javac包里的相关api实现的。先放一段效果图

java 如何循环执行一个对象_写一个在线Java脚本执行器

写一个在线Java脚本执行器https://www.zhihu.com/video/1233762820346097664

编译代码

public 
           

整段代码还是比较简单的

  1. 获取系统Java编译器
  2. 获取源码的类信息,比如名称,方法等等
  3. 将源码存储进StringJavaFileObject
  4. 设置cp等进行编译

大体的流程就是这几步就完成了。

整个过程中的难点是如果我们的工程是基于springboot的话,那么需要遍历springboot里面的文件夹和文件,针对springboot的处理可以参考 SpringBoot Loader 浅析

下面主要是说一下 对JavaFileManager的处理。在SpringBootLauncher里只是实现了对springboot fat jar的处理,但是具体和JavaCompiler 的融合还是在 SpringBootJavaFileManager 这个里处理的

public 
           
  1. 在构造SpringBootJavaFileManager实例的时候,开启SpringBoot fat jar的扫描。
  2. 重写 getClassLoader() 获取springboot loader里的 LaunchedURLClassLoader ,并将它设置成全局的classloader,主要是后面在执行方法时使用该classloader加载类
  3. 重写list() 方法,利用SpringBootLauncher 找到springboot fat jar里面的文件和文件夹
  4. 重写inferBinaryName() 方法,这是因为在list()方法中返回的是自定义的JarJavaFileObject,而super.inferBinaryName() 里有个校验,file 必须是 BaseFileObject,因此这里有个判断,如果是JarJavaFileObject类型,直接获取名字返回

还有一点是对于classloader的处理,因为在执行方法的时候需要将编译的class字节码加载进jvm里,所以自定义了一个classloader

public 
           

大体的思路就是这样,具体的细节可以参考 jrc

PS: 当然大家也可以选择不上传java代码,直接将本地编译好的class字节码上传就可以了,这里也就是给大家提供一个思路。

另外更加产品化的东西可以考虑接入maven api实现依赖包的搜索下载,目前只能提供手动jar包上传方式。 -------》 这个已经实现了