Java实现动态代码编译执行CodeUtil

package net.srt.utils.code;

import cn.hutool.core.io.FileUtil;
import net.srt.flink.common.context.SpringContextUtils;
import net.srt.utils.loader.DynamicClassLoader;
import net.srt.utils.loader.JavaSourceFromString;
import srt.cloud.framework.dbswitch.common.util.StringUtil;

import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author zdc
 * @description 动态代码工具类
 * @date 2025/4/24 15:34
 */
public class CodeUtil {

    private static final String ALLOWED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    public static Boolean compile(String code, String className) {
        return compile(null, code, className);
    }

    /**
     * @param classPath 编译后的存放路径
     * @param code      动态代码
     * @return
     */
    public static Boolean compile(String classPath, String code, String className) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
        JavaFileObject source = new JavaSourceFromString(className, code);
        Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(source);
        List<String> options;
        if (classPath != null) {
            String jarPath = SpringContextUtils.getProperty("dynamic.jar.path");
            if (StringUtil.isBlank(jarPath)) {
                jarPath = Objects.requireNonNull(CodeUtil.class.getResource("/")).getPath().substring(1) + "generated-resources/appassembler/jsw";
            }
            options = Arrays.asList("-d", classPath, "-classpath", getJarFiles(jarPath));
        } else {
            options = Collections.emptyList();
        }
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);
        Boolean call = task.call();
        if (!call) {
            for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                System.err.println("Error on line " + diagnostic.getLineNumber() + ": " + diagnostic);
            }
        }
        try {
            fileManager.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return call;
    }

    /**
     * 查找该目录下的所有的jar文件
     *
     * @param jarPath
     * @throws Exception
     */
    private static String getJarFiles(String jarPath) {
        StringBuilder jars = new StringBuilder();
        List<File> files = FileUtil.loopFiles(jarPath, pathname -> {
            if (pathname.isDirectory()) {
                return true;
            } else {
                return pathname.getName().endsWith(".jar");
            }
        });
        for (File file : files) {
            jars.append(file.getPath()).append(";");
        }
        return jars.toString();
    }

    public static Class getClass(String classPath, String code, String packagePath) {
        return getClass(classPath, code, packagePath, null);
    }

    public static Class getClass(String classPath, String code, String packagePath, String randomClassName) {
        if (randomClassName == null) {
            randomClassName = generateRandomClassName();
        }
        DynamicClassLoader loader = new DynamicClassLoader(classPath);
        Class<?> loadedClass = null;
        try {
            loadedClass = loader.loadClass(packagePath + "." + randomClassName);
        } catch (ClassNotFoundException e) {/*e.printStackTrace();*/}
        if (loadedClass != null) {
            return loadedClass;
        }
        String oldClassName = code.substring(code.indexOf("class") + 5, code.indexOf("{"));
        code = code.replaceAll("\\bclass\\s+" + oldClassName.trim() + "\\b", "class " + randomClassName);
        if (compile(classPath, code, randomClassName)) {
            try {
                System.out.println("动态代码编译通过");
                return loader.loadClass(packagePath + "." + randomClassName);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            System.out.println("动态代码编译失败");
        }
        return null;
    }

    /**
     * 执行无参数方法
     *
     * @param classPath
     * @param code
     * @param methodName
     * @return
     */
    public static Object run(String classPath, String code, String packagePath, String methodName) {
        try {
            Class clazz = getClass(classPath, code, packagePath);
            if (clazz != null) {
                Method method = clazz.getMethod(methodName);
                return method.invoke(clazz.getDeclaredConstructor().newInstance());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 执行有参数方法
     *
     * @param classPath
     * @param code
     * @param methodName
     * @param args
     * @param parameterTypes
     * @return
     */
    public static Object runParam(String classPath, String code, String packagePath, String methodName, List<Object> args, Class<?>... parameterTypes) {
        try {
            Class clazz = getClass(classPath, code, packagePath);
            if (clazz != null) {
                Method method = clazz.getMethod(methodName, parameterTypes);
                return method.invoke(clazz.getDeclaredConstructor().newInstance(), args.toArray());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    public static Object runParam(String classPath, String code, String packagePath, String methodName, String randomClassName, List<Object> args, Class<?>... parameterTypes) {
        try {
            Class clazz = getClass(classPath, code, packagePath, randomClassName);
            if (clazz != null) {
                Method method = clazz.getMethod(methodName, parameterTypes);
                return method.invoke(clazz.getDeclaredConstructor().newInstance(), args.toArray());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    public static String generateRandomClassName() {
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder();
        sb.append("Dynamic_Rule_");
        // 首字母大写
        sb.append((char) ('D' + random.nextInt(26)));
        // 生成后续字符
        for (int i = 0; i < 15; i++) {
            sb.append(ALLOWED_CHARS.charAt(random.nextInt(ALLOWED_CHARS.length())));
        }
        return sb.toString().replaceAll("[^" + ALLOWED_CHARS + "]", "");
    }

    public static void main(String[] args) {
        String code = "public class DynamicClass {\n" +
                "    public String execute() {\n" +
                "        String result = sayHello() + calculate(3, 5);\n" +
                "        return \"[执行结果] \" + result;\n" +
                "    }\n" +
                "    public String execute(String param) {\n" +
                "        String result = sayHello() + calculate(3, 5);\n" +
                "        return \"[执行结果] \" + result+param;\n" +
                "    }\n" +
                "    private String sayHello() {\n" +
                "        return \"Hello, 动态代码! \";\n" +
                "    }\n" +
                "    private String calculate(int a, int b) {\n" +
                "        return \"计算结果: \" + (a + b);\n" +
                "    }\n" +
                "}";
        Object execute = run("E:\\codes", code, "", "execute");
        System.out.println(execute);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值