JAVA动态编译辅助类

JAVA动态编译辅助类

一、场景

平时我们学学用到在JVM运行时,动态编译.java的源代码情况,比如作为灵活的配置文件。这时候就要用到动态编译,参考下列。

二、类内容

1、引入依赖:

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

2、编写基本类,让它继承 SimpleJavaFileObject 类。

package com.songxingzhu.utils.compile;

import javax.tools.SimpleJavaFileObject;
import java.net.URI;

public class JavaSourceFromCodeString extends SimpleJavaFileObject {
    final String code;

    public JavaSourceFromCodeString(String name, String code) {
        super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }

    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return this.code;
    }
}

2、编写工具类

package com.songxingzhu.utils.context;

import java.io.File;

public class AppContext {
    public static String baseDirectory() {
        try {
            String path = ClassLoader.getSystemResource("").getPath();
            if (path==null||"".equal(path))
                return getProjectPath();
            return path;
        } catch (Exception ignored) {
        }
        return getProjectPath();
    }

    private static String getProjectPath() {
        java.net.URL url = AppContext.class.getProtectionDomain().getCodeSource()
                .getLocation();
        String filePath = null;
        try {
            filePath = java.net.URLDecoder.decode(url.getPath(), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (filePath.endsWith(".jar"))
            filePath = filePath.substring(0, filePath.lastIndexOf(File.separatorChar) + 1);
        java.io.File file = new java.io.File(filePath);
        filePath = file.getAbsolutePath();
        return filePath;
    }
}


package com.songxingzhu.utils.compile;

import org.apache.commons.io.FileUtils;
import com.songxingzhu.utils.context.AppContext;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;


public class ClassBuilder {

    public static Class<?> buildClass(String fullClassName, String codeFilePath) throws IOException, ClassNotFoundException {

        return buildClass(fullClassName, codeFilePath, "UTF-8", AppContext.baseDirectory());
    }

    public static Class<?> buildClass(String fullClassName, String codeFilePath, String charsetName, String buildOutput) throws IOException, ClassNotFoundException {
        try {
            String code = FileUtils.readFileToString(FileUtils.getFile(codeFilePath), charsetName);
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            JavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
            List<JavaFileObject> files = new ArrayList<>();
            files.add(new JavaSourceFromCodeString(fullClassName, code));
            List<String> options = new ArrayList<>();
            options.add("-classpath");
            StringBuilder sb = new StringBuilder();
            URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
            for (URL url : urlClassLoader.getURLs()) {
                sb.append(url.getFile()).append(File.pathSeparator);
            }
            options.add(sb.toString());
            options.add("-d");
            options.add(buildOutput);
            // execute the compiler
            boolean isok = compiler.getTask(null, fileManager, null, options, null, files).call();
            if (isok) {
                File root = new File(buildOutput);
                if (!root.exists()) root.mkdirs();
                URL[] urls = new URL[]{root.toURI().toURL()};
                ClassLoader classLoader = ClassBuilder.class.getClassLoader();
                Class<?> clazz = Class.forName(fullClassName, true, classLoader);
                return clazz;
            }
            return null;
        } catch (Exception ex) {
            throw ex;
        }
    }
}

JAVA动态编译辅助类
https://www.dearcloud.cn/2018/05/07/20200310-cnblogs-old-posts/20180507-JAVA动态编译辅助类/
作者
宋兴柱
发布于
2018年5月7日
许可协议