如何将外部源代码传递给Java中的线程?

时间:2019-06-29 10:52:32

标签: java jvm classloader

我的意思是我需要将源代码作为输入传递给线程,并让线程在已经运行的情况下编译并运行源代码?

如何在mapperWordCount类中将源代码传递给map函数,而在整个项目的代码运行时,我的程序需要从扫描仪中获取mapper和reducer代码,并且必须将这些代码放置在map函数中,并减少功能,您可以查看代码

按线程,我的意思是不是Java程序的主线程。

class mapper extends Thread{

    // some code 

    @Override
    public void run() {
        mapper.map(bucket,reader);
    }
}
class mapperWordCount implement Mapper{
    public void map ( Bucket bucket , Reader reader){
        // code for word count mapper , this code must be entered by scanner as input , and compiled and run while the project is running 
    }
}
class reducer extends Thread{

    // some code 

    @Override
    public void run() {
        Reducer.reduce(bucket,reader);
    }
}
class reducerWordCount implement Reducer {
    public void reduce ( Bucket bucket , MapOfKeysAndLists keyListOfKeysAndValues){
        // code for reducer , this code must be entered by scanner as input , and compiled and run while the project is running 
    }
}

1 个答案:

答案 0 :(得分:1)

首先要大加警告:必须确保要编译的代码来自哪里,因为这会产生巨大的潜力,代码注入

另一个警告:如果编译类,您将不能一遍又一遍地重复使用相同的类名,因此您的ClassLoader最终将在OOME之前吞噬掉所有RAM!仅凭这个原因就应该使您找到另一种方式! Edit :自Java 8起,不再有 PermGen空间(用于存储类元数据),而只有 Metaspace 。区别之一是Metaspace是垃圾收集的,而PermGen不是。因此应该减少发生OOME的可能性。

如果您只是想为程序添加更多动态配置,我强烈建议您看看ScriptEngine,它支持ECMAScript(非常接近JavaScript)。框(如果至少使用Oracle的HotSpot JVM)。它将节省您编写自己的ClassLoader和编译代码的开销。

也就是说,如果您仍然希望朝这个方向继续前进,我只是想在这里进行一些尝试,但是您可能必须通过JavaCompiler对象编译文件并注入内容compilation result变成ClassLoader

如果我有一台要测试的计算机,我会尝试以下操作:

std::option

除了可以在黑暗中进行全面尝试之外,还必须定义自己的ClassLoader,因为defineClass()方法受到保护。

或者,您也可以使用Runtime.exec()产生对Files[] files = ... ; // input for first compilation task JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files)); compiler.getTask(null, fileManager, null, null, null, compilationUnits).call().get(); // Compile the class and wait for it to finish Class<?> cls = null; for (JavaFileObject compiledClass : compilationUnits) { if (compiledClass.getKind() != Kind.CLASS) continue; int n; byte[] classData; try (InputStream is = compiledClass.openInputStream()) { classData = new byte[1024]; // DO A PROPER FULL READ HERE! n = is.read(classData); } // catch Exceptions here cls = myClassLoader.defineClass(className, classData, 0, n); break; } if (cls != null) { // Now, cls.newInstance() etc. } 的调用,并直接从生成的javac中读取字节码字节,甚至可以直接将其生成到类路径中。