欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java 从数据库获取源码、动态编译、方法调用,someone like u

程序员文章站 2022-06-15 20:26:43
...
 @RequestMapping("/test/load")
    @ResponseBody
    public AjaxResult classLoad(@NotBlank String key) throws Exception {
       //    String javaSrc = exampleService.findConfigByKey(key);//从数据库获取以下源码
        String javaSrc = " import com.eos.wxapp.controller.test.Singer;\n" +
                "public class ZBC implements Singer {\n" +
                "    @Override\n" +
                "    public void sing() {\n" +
                "        System.out.println(\"一首凉凉送给你\");\n" +
                "    }\n" +
                "}\n";
        String className = "ZBC";
        try {
            Test.testInvoke(className, javaSrc);
        } catch (ClassNotFoundException | IllegalAccessException
                | InstantiationException | NoSuchMethodException
                | InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return AjaxResult.success();
    }
 public static void testInvoke(String className, String source) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        final String SUFFIX = ".java";// 类名后面要跟的后缀
        // 对source进行编译生成class文件存放在Map中,这里用bytecode接收
        Map<String, byte[]> bytecode = DynamicLoader.compile(className + SUFFIX,
                source);
        // 加载class文件到虚拟机中,然后通过反射执行
        @SuppressWarnings("resource")
        DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(
                bytecode);
        Class<?> clazz = classLoader.loadClass("ZBC");
        Singer someone = (Singer) clazz.newInstance();
        someone.sing();
    }

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class DynamicLoader {

    /**
     * 通过类名和其代码(Java代码字符串),编译得到字节码,,封装于Map中,值得注意的是,
     * 平常类中就编译出来的字节码只有一个类,但是考虑到内部类的情况, 会出现返回类名及其对应类的字节码很多个类名及其字节码,所以用Map封装方便。
     *
     * @param javaName 类名
     * @param javaSrc  Java源码
     * @return map
     */
    public static Map<String, byte[]> compile(String javaName, String javaSrc) {
        // 调用java编译器接口
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager stdManager = compiler
                .getStandardFileManager(null, null, null);

        try (MemoryJavaFileManager manager = new MemoryJavaFileManager(
                stdManager)) {

            @SuppressWarnings("static-access")
            JavaFileObject javaFileObject = manager.makeStringSource(javaName,
                    javaSrc);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager,
                    null, null, null, Arrays.asList(javaFileObject));
            if (task.call()) {
                return manager.getClassBytes();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 先根据类名在内存中查找是否已存在该类,若不存在则调用 URLClassLoader的 defineClass方法加载该类
     * URLClassLoader的具体作用就是将class文件加载到jvm虚拟机中去
     *
     * @author Administrator
     *
     */
    public static class MemoryClassLoader extends URLClassLoader {
        Map<String, byte[]> classBytes = new HashMap<String, byte[]>();

        public MemoryClassLoader(Map<String, byte[]> classBytes) {
            super(new URL[0], MemoryClassLoader.class.getClassLoader());
            this.classBytes.putAll(classBytes);
        }

        @Override
        protected Class<?> findClass(String name)
                throws ClassNotFoundException {
            byte[] buf = classBytes.get(name);
            if (buf == null) {
                return super.findClass(name);
            }
            classBytes.remove(name);
            return defineClass(name, buf, 0, buf.length);
        }
    }
}

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Map;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;

/**
 * 将编译好的.class文件保存到内存当中,这里的内存也就是map映射当中
 */
@SuppressWarnings("rawtypes")
public final class MemoryJavaFileManager extends ForwardingJavaFileManager {
    private final static String EXT = ".java";// Java源文件的扩展名
    private Map<String, byte[]> classBytes;// 用于存放.class文件的内存

    @SuppressWarnings("unchecked")
    public MemoryJavaFileManager(JavaFileManager fileManager) {
        super(fileManager);
        classBytes = new HashMap<String, byte[]>();
    }

    public Map<String, byte[]> getClassBytes() {
        return classBytes;
    }

    @Override
    public void close() throws IOException {
        classBytes = new HashMap<String, byte[]>();
    }

    @Override
    public void flush() throws IOException {
    }

    /**
     * 一个文件对象,用来表示从string中获取到的source,一下类容是按照jkd给出的例子写的
     */
    private static class StringInputBuffer extends SimpleJavaFileObject {
        // The source code of this "file".
        final String code;

        /**
         * Constructs a new JavaSourceFromString.
         *
         * @param name 此文件对象表示的编译单元的name
         * @param code 此文件对象表示的编译单元source的code
         */
        StringInputBuffer(String name, String code) {
            super(toURI(name), Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
            return CharBuffer.wrap(code);
        }

        @SuppressWarnings("unused")
        public Reader openReader() {
            return new StringReader(code);
        }
    }

    /**
     * 将Java字节码存储到classBytes映射中的文件对象
     */
    private class ClassOutputBuffer extends SimpleJavaFileObject {
        private String name;

        /**
         * @param name className
         */
        ClassOutputBuffer(String name) {
            super(toURI(name), Kind.CLASS);
            this.name = name;
        }

        @Override
        public OutputStream openOutputStream() {
            return new FilterOutputStream(new ByteArrayOutputStream()) {
                @Override
                public void close() throws IOException {
                    out.close();
                    ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
                    // 这里需要修改
                    classBytes.put(name, bos.toByteArray());
                }
            };
        }
    }

    @Override
    public JavaFileObject getJavaFileForOutput(
            JavaFileManager.Location location, String className,
            JavaFileObject.Kind kind, FileObject sibling) throws IOException {
        if (kind == JavaFileObject.Kind.CLASS) {
            return new ClassOutputBuffer(className);
        } else {
            return super.getJavaFileForOutput(location, className, kind,
                    sibling);
        }
    }

    public static JavaFileObject makeStringSource(String name, String code) {
        return new StringInputBuffer(name, code);
    }

    static URI toURI(String name) {
        File file = new File(name);
        if (file.exists()) {// 如果文件存在,返回他的URI
            return file.toURI();
        } else {
            try {
                final StringBuilder newUri = new StringBuilder();
                newUri.append("mfm:///");
                newUri.append(name.replace('.', '/'));
                if (name.endsWith(EXT)) {
                    newUri.replace(newUri.length() - EXT.length(),
                            newUri.length(), EXT);
                }
                return URI.create(newUri.toString());
            } catch (Exception exp) {
                return URI.create("mfm:///com/sun/script/java/java_source");
            }
        }
    }
}
package com.xx.xx.controller.test;
/**
 * @author Maple
 * @Description:
 * @date 2021/1/2510:42
 */
public interface Singer {
    public void sing();
}