我是靠谱客的博主 背后吐司,最近开发中收集的这篇文章主要介绍Java类文件动态编译并执行方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

package com.example.demo.dimension;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Stack;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
/**
* @ClassName: CompilerTest
* @Description: JAVA源文件动态编译
* @date: 2018年7月16日 上午9:45:32
*
*/
public class CompilerTest {
public static void main(String[] args) throws Exception {
String classPath = "G:/deleted/apktool/dynamicClass" ;
System.out.println( calculate("1.0+1.0",classPath));
}
/**
* @Title: testHello
* @Description: 测试动态编译java文件
* @param: @param classPath
* @return: void
* @throws
*/
public static void testHello(String classPath){
String className = "Main" ;
String source = "public class "+className+" { public static void main(String[] args) {System.out.println("Hello World!");} }";
boolean isSuccess = complie(source,className,classPath) ;
System.out.println( "Complie successfully:"+isSuccess );
}
/**
* @Title: calculate
* @Description: 测试动态编译并且加载类并执行对应方法
* @param: @param expr
* @param: @param classPath
* @param: @return
* @param: @throws Exception
* @return: double
* @throws
*/
private static double calculate(String expr,String classPath) throws
Exception {
String className = "Main";
String methodName = "calculate";
String source = "public class " + className + " { public static double " + methodName + "() { return " + expr
+ "; } }";
// 省略动态编译Java源代码的相关代码,参见上一节
boolean result = complie(source,className, classPath);
if (result) {
loadClass( new File(classPath) );
ClassLoader loader = CompilerTest.class.getClassLoader();
try {
Class<?> clazz = loader.loadClass(className);
Method method = clazz.getMethod(methodName, new Class<?>[] {});
Object value = method.invoke(null, new Object[] {});
return (Double) value;
} catch (Exception e) {
throw new
Exception("内部错误。",e);
}
} else {
throw new
Exception("错误的表达式。");
}
}
/**
* @Title: complie
* @Description: 动态编译java类成成class文件放入指定目录
* @param: @param expr
* @param: @param classPath
* @param: @return
* @param: @throws Exception
* @throws
*/
public static boolean complie(String source,String className,String classPath){
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
StringSourceJavaObject sourceObject = null;
try {
Iterable<String> options = Arrays.asList("-d", classPath);
sourceObject = new CompilerTest.StringSourceJavaObject(className, source);
Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
CompilationTask task = compiler.getTask(null, fileManager, null, options, null, fileObjects);
boolean result = task.call();
return result ;
} catch (URISyntaxException e) {
e.printStackTrace();
}
return false ;
}
private static class StringSourceJavaObject extends SimpleJavaFileObject {
private String content = null;
public StringSourceJavaObject(String name, String content) throws URISyntaxException {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return content;
}
}
/**
* @Title: loadClass
* @Description: 动态加载class文件
* @param: @param clazzPath
* @param: @throws Exception
* @return: void
* @throws
*/
public static void loadClass(File clazzPath) throws Exception{
// 设置class文件所在根路径
// 例如/usr/java/classes下有一个test.App类,则/usr/java/classes即这个类的根路径,而.class文件的实际位置是/usr/java/classes/test/App.class
//
File clazzPath = new File(class文件所在根路径);
// 记录加载.class文件的数量
int clazzCount = 0;
//only handle the folder
if( clazzPath.isFile() ){
clazzPath = clazzPath.getParentFile() ;
}
if (clazzPath.exists() && clazzPath.isDirectory()) {
// 获取路径长度
int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;
Stack<File> stack = new Stack<>();
stack.push(clazzPath);
// 遍历类路径
while (stack.isEmpty() == false) {
File path = stack.pop();
File[] classFiles = path.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getName().endsWith(".class");
}
});
for (File subFile : classFiles) {
if (subFile.isDirectory()) {
stack.push(subFile);
} else {
if (clazzCount++ == 0) {
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
boolean accessible = method.isAccessible();
try {
if (accessible == false) {
method.setAccessible(true);
}
// 设置类加载器
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
// 将当前类路径加入到类加载器中
method.invoke(classLoader, clazzPath.toURI().toURL());
} finally {
method.setAccessible(accessible);
}
}
// 文件名称
String className = subFile.getAbsolutePath();
className = className.substring(clazzPathLen, className.length() - 6);
className = className.replace(File.separatorChar, '.');
// 加载Class类
Class.forName(className);
System.out.println( String.format( "读取应用程序类文件[class=%s]", className) );
}
}
}
}
}
}


参考:

动态加载jar和class文件    https://blog.csdn.net/mousebaby808/article/details/31788325

JAVA源文件动态编译       https://blog.csdn.net/m1993619/article/details/78734682


最后

以上就是背后吐司为你收集整理的Java类文件动态编译并执行方法的全部内容,希望文章能够帮你解决Java类文件动态编译并执行方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部