Java是动态语言吗?JavaCompiler实现动态编译,并通过反射赋值

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

@Override

public String toString() {

return “Student [id=” + id + “, name=” + name + “]”;

}

}

2、Java文件 -> class -> jar -> 动态编辑 -> 反射赋值

private void test01() throws Exception {

final String javaPath = “D:\test\java”;

final String studentPath = javaPath + “\Student.java”;

final String jarPath = “D:\test\jar\student-1.0.0.jar”;

final String packageStudentPath = “com.guor.bean.Student”;

// 将java源文件编译成.class字节码文件

String cmd = "javac " + studentPath;

System.out.println(cmd);

boolean execSysCmd = execCmd(cmd);

System.out.println(execSysCmd);

// 打成jar包

cmd = "jar -cvf " + jarPath + " " + javaPath;

System.out.println(cmd);

execSysCmd = execCmd(cmd);

System.out.println(execSysCmd);

/**

  • URLClassLoader:继承自SecureClassLoader,支持从jar文件和文件夹中获取class,

  • 继承于classload,加载时首先去classload里判断是否由bootstrap classload加载过

*/

URL url = new URL(“file:” + jarPath);

URLClassLoader classLoader = new URLClassLoader(new URL[] { url },

Thread.currentThread().getContextClassLoader());

CusCompiler compiler = new CusCompiler(classLoader);

File file = new File(studentPath);

String beanTxt = FileUtils.readFileToString(file, “utf-8”);

Map<String, byte[]> results = compiler.compile(packageStudentPath, beanTxt);

Class<?> clazz = compiler.loadClass(packageStudentPath, results);

Object object = clazz.newInstance();

Method method = clazz.getDeclaredMethod(“setId”, Integer.class);

method.invoke(object, 1);

method = clazz.getDeclaredMethod(“setName”, String.class);

method.invoke(object, “哪吒”);

System.out.println(object);

method = clazz.getDeclaredMethod(“hello”, String.class);

method.invoke(object, “我命由我不由天”);

}

3、执行cmd命令

private boolean execCmd(String cmd) {

try {

Runtime rt = Runtime.getRuntime();

Process proc = rt.exec(cmd);

InputStream es = proc.getErrorStream();

String line;

BufferedReader br;

br = new BufferedReader(new InputStreamReader(es, “GBK”));

StringBuffer buffer=new StringBuffer();

while ((line = br.readLine()) != null) {

buffer.append(line+“\n”);

}

} catch (Exception e) {

return false;

}

return true;

}

六、编译非文件形式源代码


1、通过JavaCompiler动态编译

public static void test() {

try {

String beanName = “Student”;

String appendTxt = “private String realName”;

AppendBeanUtil.appendBean(beanName, appendTxt);

//动态编译

JavaCompiler javac = ToolProvider.getSystemJavaCompiler();

String className = “D:\workspace\yygh_parent\myTest\src\main\java\com\guor\bean\Student.java”;

int status = javac.run(null, null, null, “-d”, System.getProperty(“user.dir”)+“\target\classes”,className);

if(status!=0){

System.out.println(“没有编译成功!”);

}

ClassLoader classLoader = Student.class.getClassLoader();

Class<?> classLoad = classLoader.loadClass(Student.class.getName());

Object newInstance = classLoad.newInstance();

Method setName = classLoad.getDeclaredMethod(“setName”, String.class);

setName.invoke(newInstance,“哪吒”);

System.out.println(“动态载入属性成功+++++”+newInstance);

} catch (Exception e) {

System.out.println(e);

}

}

2、springboot中动态编译工程内存在的bean

JDK 6 的编译器 API 的另外一个强大之处在于,它可以编译的源文件的形式并不局限于文本文件。JavaCompiler 类依靠文件管理服务可以编译多种形式的源文件。比如直接由内存中的字符串构造的文件,或者是从数据库中取出的文件。这种服务是由 JavaFileManager 类提供的。

在Java SE6中最佳的方法是使用StandardJavaFileManager类。这个类能非常好地控制输入、输出,并且能通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现。新的 JDK 定义了 javax.tools.FileObject 和 javax.tools.JavaFileObject 接口。任何类,只要实现了这个接口,就可以被 JavaFileManager 识别。

使用StandardJavaFileManager步骤:

  1. 建立一个DiagnosticCollector实例

  2. 通过JavaCompiler.getStandardFileManager()方法得到一个StandardFileManager对象。

  3. 使用StandardFileManager获取需要编译的源代码。从文件或者字符流中获取源代码。

  4. JavaCompiler.getTask()生成编译任务抽象。

  5. 通过CompilationTask.call()方法编译源代码。

  6. 关闭StandardFileManager。

代码实例:

(1)动态编译工程内存在的bean

private void test02() {

try {

String beanName = “Student”;

String appendTxt = “private String realName;”;

AppendBeanUtil.appendBean(beanName, appendTxt);

String class_name = “com.guor.bean.Student”;

URLClassLoader contextClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();

CusCompiler compiler = new CusCompiler(contextClassLoader);

String script = FileUtils.readFileToString(new File(“D:\workspace\yygh_parent\myTest\src\main\java\com\guor\bean\Student.java”),“utf-8”);

Map<String, byte[]> results = compiler.compile(class_name, script);

Class<?> clazz = compiler.loadClass(class_name, results);

System.out.println(“+++++++”+clazz);

Object newInstance = clazz.newInstance();

Method setName = clazz.getDeclaredMethod(“setRealName”, String.class);

setName.invoke(newInstance,“哪吒”);

System.out.println(“动态载入属性成功+++++”+newInstance);

} catch (Exception e) {

System.out.println(e);

}

}

(2)Compiler工具类

import javax.lang.model.element.Modifier;

import javax.lang.model.element.NestingKind;

import javax.tools.*;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.*;

import java.net.*;

import java.nio.CharBuffer;

import java.util.*;

import java.util.jar.JarEntry;

public class CusCompiler {

private final static Logger log = LoggerFactory.getLogger(CusCompiler.class);

static class CustomJavaFileObject implements JavaFileObject {

private String binaryName;

private URI uri;

private String name;

public String binaryName() {

return binaryName;

}

public CustomJavaFileObject(String binaryName, URI uri) {

this.uri = uri;

this.binaryName = binaryName;

name = uri.getPath() == null ? uri.getSchemeSpecificPart() : uri.getPath();

}

@Override

public Kind getKind() {

return Kind.CLASS;

}

@Override

public boolean isNameCompatible(String simpleName, Kind kind) {

String baseName = simpleName + kind.extension;

return kind.equals(getKind()) && (baseName.equals(getName()) || getName().endsWith(“/” + baseName));

}

@Override

public NestingKind getNestingKind() {

throw new UnsupportedOperationException();

}

@Override

public Modifier getAccessLevel() {

throw new UnsupportedOperationException();

}

@Override

public URI toUri() {

return uri;

}

@Override

public String getName() {

return name;

}

@Override

public InputStream openInputStream() throws IOException {

return uri.toURL().openStream();

}

@Override

public OutputStream openOutputStream() throws IOException {

throw new UnsupportedOperationException();

}

@Override

public Reader openReader(boolean ignoreEncodingErrors) throws IOException {

throw new UnsupportedOperationException();

}

@Override

public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {

throw new UnsupportedOperationException();

}

@Override

public Writer openWriter() throws IOException {

throw new UnsupportedOperationException();

}

@Override

public long getLastModified() {

return 0;

}

@Override

public boolean delete() {

throw new UnsupportedOperationException();

}

}

static class MemoryInputJavaFileObject extends SimpleJavaFileObject {

final String code;

MemoryInputJavaFileObject(String name, String code) {

super(URI.create(name.replaceAll(“\.”, “/”) + Kind.SOURCE.extension), Kind.SOURCE);

this.code = code;

}

@Override

public CharBuffer getCharContent(boolean ignoreEncodingErrors) {

return CharBuffer.wrap(code);

}

}

static class MemoryOutputJavaFileObject extends SimpleJavaFileObject {

final String name;

Map<String, byte[]> class_out;

MemoryOutputJavaFileObject(String name, Map<String, byte[]> out) {

super(URI.create(name.replaceAll(“\.”, “/”) + Kind.SOURCE.extension), Kind.CLASS);

this.name = name;

this.class_out = out;

}

@Override

public OutputStream openOutputStream() {

return new FilterOutputStream(new ByteArrayOutputStream()) {

@Override

public void close() throws IOException {

out.close();

ByteArrayOutputStream bos = (ByteArrayOutputStream) out;

class_out.put(name, bos.toByteArray());

}

};

}

}

static class SpringBootJarFileManager implements JavaFileManager {

private URLClassLoader classLoader;

private StandardJavaFileManager standardJavaFileManager;

final Map<String, byte[]> classBytes = new HashMap<>();

SpringBootJarFileManager(StandardJavaFileManager standardJavaFileManager, URLClassLoader systemLoader) {

this.classLoader = new URLClassLoader(systemLoader.getURLs(), systemLoader);

this.standardJavaFileManager = standardJavaFileManager;

}

@Override

public ClassLoader getClassLoader(Location location) {

return classLoader;

}

private List find(String packageName) {

List result = new ArrayList<>();

String javaPackageName = packageName.replaceAll(“\.”, “/”);

try {

Enumeration urls = classLoader.findResources(javaPackageName);

while (urls.hasMoreElements()) {

URL ll = urls.nextElement();

String ext_form = ll.toExternalForm();

String jar = ext_form.substring(0, ext_form.lastIndexOf(“!”));

String pkg = ext_form.substring(ext_form.lastIndexOf(“!”) + 1);

JarURLConnection conn = (JarURLConnection) ll.openConnection();

conn.connect();

Enumeration jar_items = conn.getJarFile().entries();

while (jar_items.hasMoreElements()) {

JarEntry item = jar_items.nextElement();

if (item.isDirectory() || (!item.getName().endsWith(“.class”))) {

continue;

}

if (item.getName().lastIndexOf(“/”) != (pkg.length() - 1)) {

continue;

}

String name = item.getName();

URI uri = URI.create(jar + “!/” + name);

String binaryName = name.replaceAll(“/”, “.”);

binaryName = binaryName.substring(0, binaryName.indexOf(JavaFileObject.Kind.CLASS.extension));

result.add(new CustomJavaFileObject(binaryName, uri));

}

}

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

@Override

public Iterable list(Location location, String packageName, Set<JavaFileObject.Kind> kinds,

boolean recurse) throws IOException {

Iterable ret = null;

if (location == StandardLocation.PLATFORM_CLASS_PATH) {

ret = standardJavaFileManager.list(location, packageName, kinds, recurse);

} else if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {

ret = find(packageName);

if (ret == null || (!ret.iterator().hasNext())) {

ret = standardJavaFileManager.list(location, packageName, kinds, recurse);

}

} else {

ret = Collections.emptyList();

}

return ret;

}

@Override

public String inferBinaryName(Location location, JavaFileObject file) {

String ret = “”;

if (file instanceof CustomJavaFileObject) {

ret = ((CustomJavaFileObject) file).binaryName;

} else {

ret = standardJavaFileManager.inferBinaryName(location, file);

}

return ret;

}

@Override

public boolean isSameFile(FileObject a, FileObject b) {

throw new UnsupportedOperationException();

}

@Override

public boolean handleOption(String current, Iterator remaining) {

return standardJavaFileManager.handleOption(current, remaining);

}

@Override

public boolean hasLocation(Location location) {

return location == StandardLocation.CLASS_PATH || location == StandardLocation.PLATFORM_CLASS_PATH;

}

@Override

public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind)

throws IOException {

throw new UnsupportedOperationException();

}

@Override

public FileObject getFileForInput(Location location, String packageName, String relativeName)

throws IOException {

throw new UnsupportedOperationException();

}

@Override

public FileObject getFileForOutput(Location location, String packageName, String relativeName,

FileObject sibling) throws IOException {

throw new UnsupportedOperationException();

}

@Override

public void flush() throws IOException {

}

@Override

public void close() throws IOException {

classBytes.clear();

}

@Override

public int isSupportedOption(String option) {

return -1;

}

public Map<String, byte[]> getClassBytes() {

return new HashMap<String, byte[]>(this.classBytes);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值