`
weiqingfei
  • 浏览: 317447 次
  • 性别: Icon_minigender_1
  • 来自: 黑洞
社区版块
存档分类
最新评论

内存中动态compile,load,invoke

    博客分类:
  • Java
阅读更多

java 6以,jdk里提供了一套编译方法类,可以动态编译java source。

下面这个例子是编译字符串形式的source,直接得到编译后的class的字节进行load。

 

package jp.co.wqf;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.ForwardingJavaFileObject;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject.Kind;

import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Compile {

	public static void main(String[] args) {
		String source1 = "package jp.co.wqf; "
				+ "public class Test1 { "
				+ "public static void main(String[] args) {"
				+ "System.out.println(\"this is class Test1\");"
				+ "} "
				+ "}";
		String source2 = "package jp.co.wqf; "
				+ "public class Test2 { "
				+ "public static void main(String[] args) {"
				+ "System.out.println(\"this is class Test2\");"
				+ "} "
				+ "}";
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		//标准文件管理器,如果只使用它的话,编译出的class是文件形式
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
		BytesClassJavaFileManager classJavaFileManager = new BytesClassJavaFileManager(fileManager);
		SimpleJavaFileObject javaFileObject1 = new StringSourceJavaObject("jp.co.wqf.Test1", source1);
		SimpleJavaFileObject javaFileObject2 = new StringSourceJavaObject("jp.co.wqf.Test2", source2);
		Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(javaFileObject1,javaFileObject2);
		CompilationTask task = compiler.getTask(null, classJavaFileManager, null, null, null, fileObjects);
		boolean result = task.call();
		if (result) {
			BytesClassLoader loader = new BytesClassLoader();
			try {
				String className = "jp.co.wqf.Test2";
				Class<?> clazz = loader.loadClass(className,classJavaFileManager.getClassJavaObject(className));
				Method method = clazz.getMethod("main", new Class<?>[]{String[].class});
				method.invoke(null, new Object[] {new String[]{}});
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
}

//字符串形式的source类
class StringSourceJavaObject extends SimpleJavaFileObject{
	
	private String content = null;
	protected StringSourceJavaObject(String name, String content) {
		super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.content = content;
	}
	@Override
	public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return content;
     }
}
//字节形式的class类
class BytesClassJavaObject extends ForwardingJavaFileObject<JavaFileObject>{
	private ByteArrayOutputStream bos;
	protected BytesClassJavaObject(JavaFileObject fileObject) {
		super(fileObject);
		this.bos = new ByteArrayOutputStream();
	}
	
	@Override
	public OutputStream openOutputStream() throws IOException {
		return bos;
	}
	
	public ByteArrayOutputStream getBos() {
		return bos;
	}
}
//class类的管理器
class BytesClassJavaFileManager extends ForwardingJavaFileManager<JavaFileManager>{
	private Map<String, BytesClassJavaObject> map= new HashMap<String, BytesClassJavaObject>();  
	protected BytesClassJavaFileManager(JavaFileManager fileManager) {
		super(fileManager);
	}
	@Override
	public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling)
			throws IOException {
		JavaFileObject jfo = super.getJavaFileForOutput(location, className, kind, sibling);
		BytesClassJavaObject classJavaObject = new BytesClassJavaObject(jfo);
		map.put(className, classJavaObject);
		return classJavaObject;
	}
	public BytesClassJavaObject getClassJavaObject(String className) {
		return this.map.get(className);
	}
	
}
//用于装载字节的classloader
class BytesClassLoader extends ClassLoader{
    public Class<?> loadClass(String fullName, BytesClassJavaObject bcjo) {
        byte[] classData = bcjo.getBos().toByteArray();
        return this.defineClass(fullName, classData, 0, classData.length);
    }
}

 

转载一个通用方法

https://ironrhino.googlecode.com/svn/trunk/ironrhino/src/org/ironrhino/core/util/JavaSourceExecutor.java

 

package org.ironrhino.core.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.ForwardingJavaFileObject;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class JavaSourceExecutor {

	public static void execute(String code, String... args) throws Exception {
		Class<?> clazz = compile(code);
		Method method = clazz.getMethod("main", new Class[] { String[].class });
		if (method.getReturnType() == Void.TYPE) {
			int mod = method.getModifiers();
			if (Modifier.isStatic(mod) && Modifier.isPublic(mod))
				method.invoke(null, new Object[] { args });
		}
	}

	public static Class<?> compile(String code) throws Exception {
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager stdFileManager = compiler
				.getStandardFileManager(null, null, null);
		JavaFileManager fileManager = new ForwardingJavaFileManager<StandardJavaFileManager>(
				stdFileManager) {

			@Override
			public JavaFileObject getJavaFileForOutput(Location location,
					final String className, Kind kind, FileObject sibling)
					throws IOException {
				JavaFileObject jfo = super.getJavaFileForOutput(location,
						className, kind, sibling);
				return new ForwardingJavaFileObject<JavaFileObject>(jfo) {

					@Override
					public OutputStream openOutputStream() throws IOException {
						ByteArrayOutputStream bos = new ByteArrayOutputStream();
						ByteArrayClassLoader.getInstance().defineClass(
								className, bos);
						return bos;
					}
				};
			}
		};
		code = complete(code);
		JavaSource source = new JavaSource(extractClassName(code), code);
		List<JavaFileObject> list = new ArrayList<JavaFileObject>();
		list.add(source);
		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
		compiler.getTask(null, fileManager, diagnostics, null, null, list)
				.call();
		fileManager.close();
		List<Diagnostic<? extends JavaFileObject>> diagnos = diagnostics
				.getDiagnostics();
		if (diagnos.size() > 0) {
			StringBuilder sb = new StringBuilder();
			for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics
					.getDiagnostics()) {
				sb.append("Error [");
				sb.append(diagnostic.getMessage(null));
				sb.append("] on line ");
				sb.append(diagnostic.getLineNumber());
				sb.append(" in  ");
				sb.append(diagnostic.getSource().toUri());
			}
			throw new RuntimeException(sb.toString());
		}
		return ByteArrayClassLoader.getInstance().loadClass(
				source.getClassName());
	}

	private static String complete(String code) {
		String className = extractClassName(code);
		if (className == null) {
			className = "C" + System.currentTimeMillis();
			StringBuilder sb = new StringBuilder();
			sb.append("public class ");
			sb.append(className);
			sb.append("{public static void main(String... args){");
			sb.append(code);
			sb.append("}}");
			code = sb.toString();
		}
		return code;
	}

	private static Pattern PACKAGE = Pattern.compile("package\\s+(\\w+)");
	private static Pattern CLASS = Pattern.compile("class\\s+(\\w+)");

	private static String extractClassName(String code) {
		String p = null;
		String c = null;
		Matcher m = PACKAGE.matcher(code);
		if (m.find())
			p = m.group(1);
		Matcher m2 = CLASS.matcher(code);
		if (m2.find())
			c = m2.group(1);
		if (c == null)
			return null;
		else
			return p == null ? c : p + "." + c;
	}

	static class JavaSource extends SimpleJavaFileObject {

		private String code;

		private String className;

		JavaSource(String className, String code) {
			super(URI.create("string:///" + className.replace('.', '/')
					+ Kind.SOURCE.extension), Kind.SOURCE);
			this.className = className;
			this.code = code;
		}

		@Override
		public CharSequence getCharContent(boolean ignoreEncodingErrors) {
			return code;
		}

		public String getClassName() {
			return className;
		}

	}

	static class ByteArrayClassLoader extends ClassLoader {

		private static ByteArrayClassLoader instance = AccessController
				.doPrivileged(new PrivilegedAction<ByteArrayClassLoader>() {
					@Override
					public ByteArrayClassLoader run() {
						return new ByteArrayClassLoader();
					}
				});

		private Map<String, ByteArrayOutputStream> bytes = new HashMap<String, ByteArrayOutputStream>();

		public static ByteArrayClassLoader getInstance() {
			return instance;
		}

		@Override
		public Class<?> findClass(String name) {
			byte[] classData = bytes.remove(name).toByteArray();
			return defineClass(name, classData, 0, classData.length);
		}

		public void defineClass(String name, ByteArrayOutputStream b) {
			bytes.put(name, b);
		}

	}

}

 

分享到:
评论

相关推荐

    内存中动态编译执行java代码

    内存中动态编译执行Java代码是一种高级编程技巧,它允许我们在程序运行时根据需要创建、编译和执行新的Java代码。这种技术在某些场景下非常有用,比如在元编程、插件系统、自定义脚本执行或者代码热更新中。在Java中...

    Java动态编译Java代码,运行在内存中,并执行

    通过java的ToolProvider创建JavaCompile,用来执行class源文件 * 4.创建DiagnosticCollector用来执行获取执行失败的错误结果 * 5.添加动态执行的编译环境 options 是个集合,添加内容,字符集,classpath等 * 6....

    compile_compile

    compile

    compile_protobuf_protobuf:compile_protobuf_

    在标签"protobuf:compile protobuf"中,"protobuf"是指protobuf库本身,而"compile protobuf"是指执行protobuf编译器`protoc`来生成目标语言的代码。这个过程通常分为以下几个步骤: 1. **定义消息类型**:在.proto...

    Design Compile 介绍.7z

    5. **功耗管理**:探讨如何通过低功耗设计技术,如多电压域、动态电压频率调整(DVFS),在Design Compile中实现低功耗优化。 6. **设计迭代与优化**:展示如何利用Design Compile的反馈机制进行设计迭代,以逐步...

    Compile-CC编译器源代码

    Compile-CC源代码中的词法分析器会读取源程序文本,将字符流转化为有意义的符号(token)流。这些符号是编译器理解和处理的基础,如关键字、标识符、常量、运算符等。词法分析器通常使用正则表达式来识别不同的token...

    Vue 中的compile操作方法

    Vue 中的 Compile 操作方法 Vue 中的 Compile 操作方法是指 Vue 框架中将模板编译为可执行的 JavaScript 代码的过程。这个过程对 Vue 的性能和可扩展性产生了重要的影响。本文将详细介绍 Vue 中的 Compile 操作方法...

    如何运行内存中的EXE

    在IT领域,有时候出于调试、安全或性能优化的考虑,我们可能会需要将程序加载到内存中执行,而不是传统的硬盘磁盘执行。这个过程涉及到操作系统内存管理、进程管理和程序执行等核心概念。本教程将深入探讨如何实现...

    color-compile - 源码

    `color-compile`是一个实用工具,它为`gcc/g++/make`编译过程中的错误、警告和提示信息添加了颜色高亮,使得输出更加醒目,从而帮助开发者更快地识别问题所在。在某些不支持颜色输出的系统上,这个工具尤其有用。 ...

    javacompile

    2. **javacompile.dll** - 如前所述,这可能是一个与Java编译相关的动态链接库,提供了编译过程中的某些特定功能。 3. **jc.exe** - 可能是Java编译工具的可执行文件,用户可以通过这个文件运行编译任务。 4. **...

    Design Compile使用说明

    Design Compile是Synopsys公司的一款强大的综合工具,用于将高级语言(如Verilog、VHDL)编写的RTL(Register Transfer Level)代码转换为门级网表,这是数字集成电路设计流程中的关键步骤。本篇文章将深入探讨...

    python-3.2.2-xcompile.patch

    在本文中,我们将深入探讨Python 3.2.2版本中的“xcompile”补丁,即“python-3.2.2-xcompile.patch”。这个补丁是针对Python 3.2.2源代码的修改,旨在优化编译过程,提升在不同硬件平台上的兼容性和性能。 首先,...

    前端开源库-post-compile-webpack-plugin

    要使用`Post-Compile Webpack Plugin`,首先需要通过npm或yarn将其安装到项目中: ```bash npm install --save-dev post-compile-webpack-plugin # 或 yarn add --dev post-compile-webpack-plugin ``` 然后在你的...

    js-conditional-compile-loader-1.0.15.tgz

    【js-conditional-compile-loader 1.0.15】是一个专为JavaScript代码条件编译设计的加载器,用于处理项目中的环境特定代码。在软件开发中,有时我们需要根据不同的运行环境(例如开发、测试和生产)来编译不同的代码...

    Python-2.7.13-xcompile.patch

    Python-2.7.13-xcompile.patch

    compile-node-sass-0.0.3.zip

    【标题】"compile-node-sass-0.0.3.zip" 涉及的主要知识点是关于Node.js环境下的Sass编译工具,它允许开发者将Sass或SCSS语法转换成CSS,以便在Web开发中使用。Sass是一种强大的CSS预处理器,提供了变量、嵌套规则、...

    javaCompile.exe

    javaCompile.exe是一个Editplus插件。 可以简化java程序运行流程。 直接运行java,不再先编译再运行。 减少无效动作,增加开发效率。

    VC2005 X64 Compile 設定

    总之,“VC2005 X64 Compile 設定”涉及的是如何在Visual Studio C++ 2005中设置和使用64位编译环境,这对于希望在64位平台上运行C++应用程序的开发者来说是一个重要的步骤。通过上述步骤,你可以确保你的代码能够...

    Compile85.docx

    Compile

    python-2.7.3-xcompile补丁

    该补丁是为了使得python-2.7.3可以编译通过,编译的目的是未来使得python支持valgrind工具检测python程序是否存在内存泄露,具体请参考本人博客。

Global site tag (gtag.js) - Google Analytics