目录
对于一些直接使用jdk底层的代码我是很难看懂的,逐渐去看看 源码,比瞎几把coding要重要很多
起因
1。字节码生成,在spring 动态代理AOP 中,spring框架会在运行期间动态创建一个被代理对象的子类,如果我们有这种需求,应该怎么办
即程序动态的生成Java源文件,由JDK进行编译,最后动态加载到JVM并运行。
2。jdk 中带有编译器相关的Api,所以我们可以直接编译我们动态生成的java源文件
3。我要将 src.java 的文件编译成 .class文件
javaCompiler类编译文件,并且使用 URlClassLoader类加载编译好的class 文件中的方法
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, null, null, "src.java");
4。为了直接从内存中直接加载java 的源文件,我们可以使用 ForwardingJavaFileManager,继承并重写URLClassLoader.findClass()就可以实现将编译结果直接以byte[]形式返回,
实际应用
//在内存中编译String类型的Java代码
public class JavaStringCompiler {
private JavaCompiler compiler;
private String javaClassPath = null;
private StandardJavaFileManager stdManager;
public JavaStringCompiler(String javaClassPath) {
// 需要辅助加入的jar文件路径
this.javaClassPath = javaClassPath;
this.compiler = ToolProvider.getSystemJavaCompiler();
this.stdManager = compiler.getStandardFileManager(null, null, null);
}
/**
* Compile a Java source file in memory.
*
* @param fileName Java文件名, 例如:Test.java
* @param source Java源码字符串
* @return 编译结果Map<String, byte[]>
* @throws IOException If compile error.
*/
public Map<String, byte[]> compile(String fileName, String source) {
// Java编译选项
Iterable<String> options = Arrays.asList("-encoding", "UTF-8", "-classpath", javaClassPath);
// 打开当前的jar文件列表
List<File> fileList = new ArrayList<File>();
for (String str : javaClassPath.split(";")) {
if (StringUtil.isNotBlank(str)) {
try {
fileList.add(new File(str));
} catch (Exception e) {}
}
}
try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) {
JavaFileObject javaFileObject = manager.makeStringSource(fileName, source);
try {
this.stdManager.setLocation(StandardLocation.CLASS_PATH, fileList);
} catch (Exception e) {
throw new UnexCommonException("StandardLocation.CLASS_PATH setting failed.", e);
}
CompilationTask task = compiler.getTask(null, manager, null, options, null, Arrays.asList(javaFileObject));
Boolean result = task.call();
if (result == null || !result.booleanValue()) {
throw new UnexBaseException("Compilation failed.");
}
return manager.getClassBytes();
} catch (Exception e) {
throw new UnexBaseException("Compilation failed.");
}
}
/**
* 根据编辑的class信息加载相应的class对象
*
* @param name 完整的Class名称
* @param classBytes 编译的Class对应的Map对象
* @return Class对象:Class<?>
* @throws ClassNotFoundException
* @throws IOException
*/
public Class<?> loadClass(String name, Map<String, byte[]> classBytes) throws ClassNotFoundException,IOException {
try ( MemoryClassLoader classLoader = new UnexMemoryClassLoader(classBytes)) {
return classLoader.loadClass(name);
}
}
}
内存class 加载器
/**
* 内存Class加载器
*/
public class MemoryClassLoader extends URLClassLoader {
// class name to class bytes:
private static Map<String, byte[]> CLASS_BYTES_MAP = new HashMap<String, byte[]>();
private static Map<String, Class<?>> DEFINED_CLASS_MAP = new HashMap<String, Class<?>>();
public UnexMemoryClassLoader() {
super(new URL[0], UnexMemoryClassLoader.class.getClassLoader());
}
public MemoryClassLoader(Map<String, byte[]> classBytes) {
this();
for (String key : classBytes.keySet()) {
if (!CLASS_BYTES_MAP.containsKey(key)) {
logger.debug("UnexMemoryClassLoader():::" + key);
CLASS_BYTES_MAP.put(key, classBytes.get(key));
}
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> definedClass = DEFINED_CLASS_MAP.get(name);
if (definedClass != null) {
logger.debug("findClass() end:::DEFINED_CLASS_MAP found.");
return definedClass;
}
byte[] buf = CLASS_BYTES_MAP.get(name);
if (buf == null) {
return this.getClass().getClassLoader().loadClass(name);
}
definedClass = defineClass(name, buf, 0, buf.length);
DEFINED_CLASS_MAP.put(name, definedClass);
logger.debug("findClass() end:::" + name);
return definedClass;
}
/**
* @param name
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> loadedClass = loadClass(name, false);
logger.debug("loadClass() end:::loadedClass=" + loadedClass);
return loadedClass;
}
}