在java项目内获取整个电脑任意位置的.class文件进行实例化,执行以下案例时,需要从jdk中引入tool.jar 文件
第一种:使用urlclassloader进行
package test;
import java.net.URL;
import java.net.URLClassLoader;
/**
* @ClassName Test
* @Description
* @Date 2021/11/26 11:06
**/
public class TestURLClassLoader {
public static void main(String[] args) throws Exception{
//.class 路径地址
URL[] urls = new URL[] {new URL("file:/"+"F:\\CODE\\STC-SLIT\\STC-tbook\\sc-app-stc-quant-sdk\\filed\\TestStrategy.class")};
//load 到内存中
URLClassLoader loader = new URLClassLoader(urls);
//进行反射获取
Class c = loader.loadClass("com.stc.quant.TestStrategy");
//实例化
Object o = c.newInstance();
System.out.println("c = " + c);
//获取当前实例对象的方法,invoke(o, null) ,o为实例对象
Object getQuantId = c.getMethod("getQuantId").invoke(o, null);
System.out.println("getQuantId = " + getQuantId);
}
}
第二种:使用二进制对class文件实例
package test;
import sun.misc.IOUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* 二进制转换,继承classloader
* @Description
* @Date 2021/11/24 10:38
**/
public class TestClassLoader extends ClassLoader {
private String className;
//转换byte后的字节码
private byte[] classBytes;
private TestClassLoader(String className, String localPath) throws IOException {
this.className = className;
this.classBytes = this.getByteClass(localPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//只处理classloader.test类
if (name.equals(className)) {
//调用definClass将一个字节流定义为一个类。
return defineClass(className, classBytes, 0, classBytes.length);
}
return super.findClass(name);
}
public static void main(String[] args) throws Exception {
String className = "com.stc.quant.TestStrategy";
String localPath = "F:\\CODE\\STC-SLIT\\STC-tbook\\sc-app-stc-quant-sdk\\filed\\TestStrategy.class";
//创建加载器
TestClassLoader clt = new TestClassLoader(className,localPath);
//使用我们自定义的类去加载className
Class clazz = clt.loadClass(className);
//反射创建test类对象
Object test = clazz.newInstance();
//反射获取方法
Method method = test.getClass().getMethod("getQuantId");
//反射去调用执行方法
String str = (String) method.invoke(test);
System.out.println(str);
}
public byte[] getByteClass(String localPath) throws IOException {
FileInputStream fis = new FileInputStream(localPath);
byte[] classBytes = IOUtils.readFully(fis, -1, false);
return classBytes;
}
}
第三种:将字符串实例化为一个对象,业务方面需要把java类上传到数据库中,由数据库取出对字符串进行实例化。因没有进行数据库操作,则定义一个java类进行读取,然后传入JavaCompiler.CompilationTask中进行编译操作
首先先看一下源码里面的讲解,里面的参数都是什么
为具有给定组件和参数的编译任务创建未来。编译可能没有按照CompilationTask界面中的描述完成。
如果提供了文件管理器,它必须能够处理StandardLocation中定义的所有位置。
请注意,注释处理既可以处理要编译的源代码的编译单元(通过compilationUnits参数传递),也可以处理类文件(其名称通过classes参数传递)。
参数:
out–用于从编译器获得额外输出的写入程序;如果为空,请使用System.err
fileManager–文件管理器;如果为null,则使用编译器的标准文件管理器
diagnosticListener–诊断侦听器;如果为null,则使用编译器的默认方法报告诊断
选项–编译器选项,null表示没有选项
classes–注释处理要处理的类的名称,null表示没有类名
compilationUnits–要编译的编译单元,null表示没有编译单元
返回:
表示编译的对象
抛出:
RuntimeException–如果用户提供的组件中发生不可恢复的错误。原因将是用户代码中的错误。
IllegalArgumentException–如果任何选项无效,或者如果任何给定编译单元不是源代码类型
CompilationTask getTask(Writer out,
JavaFileManager fileManager,
DiagnosticListener<? super JavaFileObject> diagnosticListener,
Iterable<String> options,
Iterable<String> classes,
Iterable<? extends JavaFileObject> compilationUnits);
下面是读取字符串并进行动态编译的过程
package test;
import sc.app.stc.quant.sdk.utils.javatool.CharSequenceJavaFileObject;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.Arrays;
/**
* @ClassName StrToJavaCompile
* @Description
* @Date 2021/11/26 15:14
**/
public class TestStrToJavaCompile {
public static void main(String[] args) throws Exception {
String name = "com.stc.quant.TestStrategy";
String path = "F:\\GitTest1\\TestStrategy.java";
String s = readFile(path);
Class<?> compile = compile(name, s);
Object o = compile.newInstance();
Object getQuantId = compile.getMethod("getQuantId").invoke(o, null);
System.out.println("getQuantId = " + getQuantId);
}
/**
*
* @param className
* @param javaCodes
* @return
*/
private static Class<?> compile(String className, String javaCodes) {
//获取系统编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//此文件管理器创建一个代表普通文件对象files , zip file entries ,或类似的基于文件系统的容器中的条目。
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
//字符串转移拼接
CharSequenceJavaFileObject srcObject = new CharSequenceJavaFileObject(className, javaCodes);
//放入JavaFileObject类中,源码中继承自FileObject类
Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(srcObject);
//-d选项指定的目录下(保留包名)
String flag = "-d";
String outDir = "";
try {
//路径获取
File classPath = new File(Thread.currentThread().getContextClassLoader().getResource("").toURI());
outDir = classPath.getAbsolutePath() + File.separator;
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
//使用编译选项可以改变默认编译行为。编译选项是一个元素为String类型的Iterable集合
Iterable<String> options = Arrays.asList(flag, outDir);
// 建立用于保存被编译文件名的对象
// 每个文件被保存在一个从JavaFileObject继承的类中
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, fileObjects);
// 编译源程序
boolean result = task.call();
if (result == true) {
try {
//如果编译成功,用类加载器加载该类
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 读取文件,一行行读取拼接为字符串
* @param path
* @return
* @throws Exception
*/
public static String readFile(String path) throws Exception{
File file = new File(path);
StringBuffer stringBuffer = new StringBuffer();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
String s = null;
while ((s = br.readLine()) != null) {
System.out.println(System.lineSeparator()+s);
stringBuffer.append(System.lineSeparator() + s);
}
System.out.println("stringBuffer.toString() = " + stringBuffer.toString());
return stringBuffer.toString();
}
}
使用到的文件转义类
package sc.app.stc.quant.sdk.utils.javatool;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import java.net.URI;
public class CharSequenceJavaFileObject extends SimpleJavaFileObject {
private CharSequence content;
public CharSequenceJavaFileObject(String className,
CharSequence content) {
super(URI.create("string:///" + className.replace('.', '/')
+ JavaFileObject.Kind.SOURCE.extension), JavaFileObject.Kind.SOURCE);
this.content = content;
}
@Override
public CharSequence getCharContent(
boolean ignoreEncodingErrors) {
return content;
}
}
还可以自定义文件管理器监听类,从监听类中获取实例
package sc.app.stc.quant.sdk.utils.javatool;
import java.io.IOException;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class ClassFileManager extends ForwardingJavaFileManager {
public JavaClassObject getJavaClassObject() {
return jclassObject;
}
private JavaClassObject jclassObject;
public ClassFileManager(StandardJavaFileManager standardManager) {
super(standardManager);
}
public JavaFileObject getJavaFileForOutput(Location location,
String className, JavaFileObject.Kind kind, FileObject sibling)
throws IOException {
jclassObject = new JavaClassObject(className, kind);
return jclassObject;
}
}
对上面的测试案例进行补充的,关注新添加的ClassFileManager类,实现一个监听
/**
* 动态编译实例
* @param fullClassName 报名加类名
* @param javaCode 代码字符串
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Object javaCodeToObject(String fullClassName, String javaCode)
throws IllegalAccessException, InstantiationException {
Object instance = null;
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));
List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
jfiles.add(new CharSequenceJavaFileObject(fullClassName, javaCode));
List<String> options = new ArrayList<String>();
options.add("-encoding");
options.add("UTF-8");
options.add("-classpath");
options.add(this.classpath);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, jfiles);
boolean success = task.call();
if (success) {
JavaClassObject jco = fileManager.getJavaClassObject();
@SuppressWarnings("resource")
DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this.parentClassLoader);
Class<?> clazz = dynamicClassLoader.loadClass(fullClassName, jco);
instance = clazz.newInstance();
} else {
String error = "";
for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
error = error + compilePrint(diagnostic);
}
logger.info("buildMessage:{}", error);
}
return instance;
}
也没写过这类东西,第一次写,都是从各大网站看到的,最后自己测试通过的,特此来进行记录一下