java动态代码,将文本运行为Java代码。

  • Post author:
  • Post category:java


原理:将文本写到文件,用Java的类加载动态运行。

1.使用jdk自带rt.jar中的javax.tools包提供的编译器(也可以用runtime运行cmd)进行编译java源文件。

2.重写类加载器达到加载指定文件夹下的类。

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

//***java 动态编译。
public class TrendsJava {

    public static void main(String[] args) {
        int i = 10;
        String code = "System.out.println(\"Hello World!\"+(13+2*5/3));";
        code += "for(int i=0;i<" + i + ";i++){";
        code += " System.out.println(Math.pow(i,2));";
        code += "}";
        try {
            run(code);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private synchronized static File compile(String code) throws Exception {
        File file = File.createTempFile("JavaRuntime", ".java", new File(Constants.BASEDIR));
        file.deleteOnExit();
// 获得类名
        String classname = getBaseFileName(file);
// 将代码输出到文件
        PrintWriter out = new PrintWriter(new FileOutputStream(file));
        out.println(getClassCode(code, classname));
        out.close();


// 编译生成的java文件
        String[] cpargs = new String[] { "-d",Constants.BASEDIR, file.getName()};

        System.out.println(System.getProperty("user.dir"));
        //动态编译
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        int status = javac.run(null, null, null, "-d", Constants.BASEDIR,Constants.BASEDIR+file.getName());
        if (status != 0) {
            throw new Exception("语法错误!");
        }
        return file;
    }
    private static synchronized void run(String code) throws Exception {
        String classname =getBaseFileName(compile(code));
        new File(Constants.BASEDIR + classname +Constants.SUFFIX)
                .deleteOnExit();
        try {
            MyClassLoader loader = new MyClassLoader();

            Class cls =  loader.findClass(classname);
            Method main = cls.getMethod("method", null);
            main.invoke(cls, null);
        } catch (Exception se) {
            se.printStackTrace();
        }
    }
    //将一块代码封装到 method函数中
    private static String getClassCode(String code, String className) {
        StringBuffer text = new StringBuffer();
        text.append("public class " + className + "{\n");
        text.append(" public static void method(){\n");
        text.append(" " + code + "\n");
        text.append(" }\n");
        text.append("}");
        return text.toString();
    }
    private static String getBaseFileName(File file) {
        String fileName = file.getName();
        if(fileName.contains(".")){
            return fileName.split("\\.")[0];
        }else {
            return fileName;
        }

    }
}

//重写类加载器达到加载指定目录的类
class MyClassLoader extends ClassLoader{

    @Override
    protected Class<?> findClass(String name) {

        String myPath =new  File( Constants.BASEDIR+ name + Constants.SUFFIX).toURI().toString();
        System.out.println(myPath);
        byte[] cLassBytes = null;
        Path path = null;
        try {
            path = Paths.get(new URI(myPath));
            cLassBytes = Files.readAllBytes(path);
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
        }
        Class clazz = defineClass(name, cLassBytes, 0, cLassBytes.length);
        return clazz;
    }

}
//常量
interface Constants{
    String BASEDIR="C:\\Users\\Administrator\\Desktop\\filejava\\";
    String SUFFIX=".class";
}



版权声明:本文为qq_35189120原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。