java代码实现编译源码并获取执行结果

1. 命令行编译
javac –d . -encoding utf-8 CompareString.java   //编译命令

//执行命令
Process process = Runtime.getRuntime().exec("java -cp D:/myjava  HelloWorld") //执行字节码
InputStream inputStream = process.getInputStream();
BufferedReader fBufferedInputStream = new BufferedReader(new InputStreamReader(inputStream)); //获取执行结果
2. 借助tools.jar实现手动编译

安装tools.jar

本地安装  C:\Program Files\Java\jdk1.8.0_251\lib\tools.jar
mvn install:install-file -Dfile=D:\tools.jar -DgroupId=com.sun -DartifactId=tools -Dversion=1.8 -Dpackaging=jar
<dependency>
	<groupId>com.sun</groupId>
	<artifactId>tools</artifactId>
	<version>1.8</version>
</dependency>

MyTest

public class MyTest {
	public static void main(String[] args) {
		System.out.println("Hello, World");
	}
}

FileURLClassLoader 自定义实现类加载器

import org.springframework.util.Assert;

import java.io.File;
import java.net.*;
import java.util.Arrays;

/**
 * 文件路径类加载器,不需要写findClass()方法及其class文件的字节流转换逻辑
 *
 * @author liuxubo
 * @date 2023/3/19 18:50
 */
public class FileURLClassLoader extends URLClassLoader {
    /**
     * 。class文件目录
     */
    private String classFileDir;

    public FileURLClassLoader(String classFileDir, ClassLoader parent) {
        super(getURL(classFileDir), parent);
    }

    public FileURLClassLoader(String classFileDir) {
        super(getURL(classFileDir));
    }

    public FileURLClassLoader(String classFileDir, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(getURL(classFileDir), parent, factory);
    }

    public FileURLClassLoader(String[] classFileDir, ClassLoader parent) {
        super(getURL(classFileDir), parent);
    }

    public FileURLClassLoader(String[] classFileDir) {
        super(getURL(classFileDir));
    }

    public FileURLClassLoader(String[] classFileDir, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(getURL(classFileDir), parent, factory);
    }

    /**
     * 将路径转为url
     *
     * @param classFileDir
     * @return
     */
    private static URL[] getURL(String classFileDir) {
        File file = new File(classFileDir);
        if (file.isFile()) {
            file = file.getParentFile();
        }
        // File to URI
        URI uri = file.toURI();
        try {
            URL[] urls = {uri.toURL()};
            return urls;
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将多个目录路径转为url
     *
     * @param classFileDirs
     * @return
     */
    private static URL[] getURL(String[] classFileDirs) {
        Assert.notNull(classFileDirs, "类目录不能为空");

        URL[] urls = new URL[classFileDirs.length];

        for (int i = 0; i < classFileDirs.length; i++) {
            File file = new File(classFileDirs[i]);
            if (file.isFile()) {
                file = file.getParentFile();
            }
            // File to URI
            URI uri = file.toURI();
            try {
                urls[i] = uri.toURL();
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }
        return urls;
    }
    }

测试

 //依赖 tools.jar 调用JavaCompiler获取编译器
 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
  // 获取文件管理器StandardJavaFileManager,用来管理要编译的.java文件
  StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, Locale.CHINA, StandardCharsets.UTF_8);

  // 获取表示给定文件的文件对象
  String fileName = "D:/upload/test/MyTest.java";
  Iterable iterable = standardJavaFileManager.getJavaFileObjects(fileName);

  // 获取编译任务的future接口CompilationTask 当调用它的call方法时,开始编译
  JavaCompiler.CompilationTask compilationTask = javaCompiler.getTask(null, standardJavaFileManager, null, null, null, iterable);
  compilationTask.call();

  // 加载 指定路径的 .class文件
  FileURLClassLoader fileURLClassLoader = new FileURLClassLoader("D:/upload/test");
  Class<?> aClass = fileURLClassLoader.loadClass("MyTest");

  //执行 main方法
  Method method = aClass.getMethod("main", String[].class);
  method.invoke(null, new Object[]{new String[0]});
3. 内存中编译执行

上面需要.java文件,编译.class文件,最后再类加载实现
这里实现内存中Java源码字符串编译执行
依赖

<dependency>
      <groupId>org.mdkt.compiler</groupId>
      <artifactId>InMemoryJavaCompiler</artifactId>
      <version>1.3.0</version>
  </dependency>

测试

    public static void main(String[] args) throws Exception {
        StringBuffer sourceCode = new StringBuffer();

        sourceCode.append("package com.yl;\n");
        sourceCode.append("public class Main {\n" +
                "\tpublic static void main(String[] args) {\n" +
                "\t\tSystem.out.println(\"Hello, World\");\n" +
                "\t}\n" +
                "}");

        Class<?> helloClass = InMemoryJavaCompiler.newInstance().compile("com.yl.Main", sourceCode.toString());
        //执行 main方法
        Method method = helloClass.getMethod("main", String[].class);
        method.invoke(null, new Object[]{new String[0]});
    }
4. beanshell脚本实现动态编译执行

2中需要.java文件,编译.class文件,最后再类加载实现
3中内存中编译执行,但是执行慢,平均1-2s
思路:jmeter中有使用beanshell,jbpm也有用到,经测试执行代码几十毫秒,效率高
依赖

 <dependency>
     <groupId>org.apache-extras.beanshell</groupId>
     <artifactId>bsh</artifactId>
     <version>2.0b6</version>
 </dependency>

测试

package com.yl.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 获取静态方法main执行结果
 *
 * @author liuxb
 * @date 2023/3/20 23:21
 */
@Slf4j
public class StaticMainUtil {

    /**
     * 获取main方法执行结果
     * @param clazz
     * @return
     */
    public static String getMain(Class<?> clazz) {
        try {
            //执行 main方法
            Method method = clazz.getMethod("main", String[].class);

            //输出流重定向
            // 改变输出语句的位置(重定向)
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(baos);
            // 把系统打印流改成我们自己的打印流
            System.setOut(ps);

            method.invoke(null, new Object[]{new String[0]});

            //必须恢复重定向
            PrintStream printStream = printConsoleStream();
            System.setOut(printStream);

            log.info("main方法执行结果:{}", baos);

            //输出打印结果
            return baos.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建控制台输出流,参考 {@link System newPrintStream(java.io.FileOutputStream, java.lang.String)}
     */
    private static PrintStream printConsoleStream() {
        OutputStream fos = new FileOutputStream(FileDescriptor.out);
        String enc = System.getProperty("sun.stdout.encoding");
        if (enc != null) {
            try {
                return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
            } catch (UnsupportedEncodingException uee) {}
        }
        return new PrintStream(new BufferedOutputStream(fos, 128), true);
    }
}

//测试方法
 public String bshCompiler(String code) {
   Interpreter interpreter = new Interpreter();
     try {
         //beanshel解释器运行,返回Class
         Class aClass = (Class) interpreter.eval(code);
         //执行 main方法
         return StaticMainUtil.getMain(aClass);
     } catch (EvalError e) {
         throw new RuntimeException(e);
     }
 }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值