`
qiang106
  • 浏览: 383744 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

JDK6 动态编译——内存字符串编译方式

阅读更多
   JDK6开始提供了动态编译的API,在许多应用场景都可以用得着,如动态加载(修改)服务、高性动态业务逻辑实现(用脚本或模板引擎实现效率满足不了需求)等都非常好用。

    API对应的接口都在javax.tools包下面,常用编译方式有基于文本文件、内存字符串等,实际上基于URI的字节流都可以,也就是远程Java源代码也可以。对于常用的已有文件形式的动态编译网上的实例已经非常多,我在这里介绍下动态编译内存中以字符串的形式。

简单的代码流程如下:

//通过系统工具提供者获得动态编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//获得一个文件管理器,它的功能主要是提供所有文件操作的规则,
//如源代码路径、编译的classpath,class文件目标目录等,其相关属性都提供默认值
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

//获得CompilationTask并调用
//获得CompilationTask方法原型:
getTask(Writer out,
     JavaFileManager fileManager,
     DiagnosticListener<? super JavaFileObject> diagnosticListener,
     Iterable<String> options,
     Iterable<String> classes,
     Iterable<? extends JavaFileObject> compilationUnits)


//简单调用例子
boolean b = jc.getTask(null, fileManager, null, null, null, compilationUnits).call();




    我这里介绍的字符串形式的编译(其它方式也会有相似的具体实现),还需要提供一个FileObject一个实现类,将相应的对象封装作为getTask()的最后一个参数来构建具体的编译Task.

JavaDoc提供的一个FileObject参考实现:

Class JavaSourceFromString

import java.net.URI;

import javax.tools.SimpleJavaFileObject;

public class JavaSourceFromString extends SimpleJavaFileObject {

	/**
     *  源码
     */
    final String code;

    /**
     * 构造方法:从字符串中构造一个FileObject
     * @param name the name of the compilation unit represented by this file object
     * @param code the source code for the compilation unit represented by this file object
     */
    JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),
              Kind.SOURCE);
        this.code = code;
    }

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



完整的测试类:
Class TestDyCompile
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import dyclass.Test;


public class TestDyCompile {

	/**
	 * 
	 * @author ZhangXiang
	 * @param args
	 * 2011-4-7
	 */
	public static void main(String[] args) {
		
		StringBuilder classStr = new StringBuilder("package dyclass;public class Foo implements Test{");
		classStr.append("public void test(){");
		classStr.append("System.out.println(\"Foo2\");}}");
		
		JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager fileManager = jc.getStandardFileManager(null, null, null);
		Location location = StandardLocation.CLASS_OUTPUT;
		File[] outputs = new File[]{new File("bin/")};
		try {
			fileManager.setLocation(location, Arrays.asList(outputs));
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		JavaFileObject jfo = new JavaSourceFromString("dyclass.Foo", classStr.toString());
		JavaFileObject[] jfos = new JavaFileObject[]{jfo};
		Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(jfos);
		boolean b = jc.getTask(null, fileManager, null, null, null, compilationUnits).call();
		if(b){//如果编译成功
			try {
				Test t = (Test) Class.forName("dyclass.Foo").newInstance();
				t.test();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}
}



我在这里的具体业务类为dyclass.Foo,也就是我们需要动态编译的类,为了方便写业务的调用代码,也可以让我们的业务类实现一个接口,然后通过反射获得具体子类强制转换来调用。

Test接口:

public interface Test {
	//业务方法签名
	void test();
}



另外,在代码中还有这么一段:

           Location location = StandardLocation.CLASS_OUTPUT;
           File[] outputs = new File[]{new File("bin/")};
		try {
			fileManager.setLocation(location, Arrays.asList(outputs));
		} catch (IOException e) {
			e.printStackTrace();
		}


这段代码的作用相信大家一看到它就想到它的作用了,前面有说过JavaFileManager 的作用,我在这里设置了CLASS文件的输出目录,意图很简单,我的工程是在Eclipse运行的,项目的目标路径就是项目下的bin目录,如果不设置的话,class文件输出路径即为默认值,也就是直接在项目根路径下,后面直接调用就不能完成了。当然在其它一些应用场景中需要设置为自己需要的目录。
同样的方法可以设置JavaFileManager 其它的我们需要的文件规则属性(可以参照枚举类型StandardLocation),在这里就不一一介绍了。

     写东西的时候往往很难静下心来,写得很马虎,多多见谅,有机会大家多一起学习。
1
0
分享到:
评论
1 楼 李_俊 2012-07-09  
当你动态import第三方jar包里的类就痛苦了。
比如:在动态类里StringBuilder classStr = new StringBuilder("
package dyclass;
import test.Test;// 这个Test类是jar包里的类。

public class Foo implements Test{");

相关推荐

    支持jdk1.8的java反编译工具 luyten

    Procyon-Decompiler支持JDK1.8类的反编译,在很多方面做得非常不错:字符串的Switch、枚举声明方面、注解方面、匿名类、内部类、Java8新接口规范、Java8 Lambda表达式、Java8 方法传递等。  luyten是Procyon的GUI,...

    源码编译工具openoj.zip

    openoj是一个可以对从一个输入流中包括文件,网络流,字符串所代表的源代码进行编译,运行,和测试的程序。现在支持对java、c和 c 的编译和运行以及测试。 openoj是一个用maven构建的,所以可以直接在eclipse中导入...

    java jdk8 学习笔记

    2.动态加载类别文档、字符串池(String Pool)等特性为节省内存而设计 3.jdk java development kit java 开发工具集 java se 平台包括jdk与java语言 ,(不知道编程语言是什么?可以这样想 :java 语言 -&gt;类文件...

    auto-string-formatter:用于Java的字符串格式化库,在编译时通过注释处理生成优化的formatter方法

    auto-string-formatter是Java的字符串格式化库,可在编译时通过注释处理生成优化的formatter方法。 auto-string-formatter具有以下功能: 使用StringBuilder就像手写代码一样快。 (大多数)兼容String.format 。...

    精通正则表达式基于.NET ASP PHP JSP JavaScript

    StringBuilderApplication/DealWithStringBuilder.aspx 动态字符串处理 第9章(/09/) RegexApplication/Default.aspx 正则表达式类的应用 RegexApplication/GetPageHtmlData.aspx 获取网页的内容 ...

    jdk-11.0.19-windows-x64-bin.zip

    JDK 11引入了“var”关键字,允许根据初始化值的类型自动推断局部变量的类型,还新增了单引号字符串支持,并增强了安全性,例如默认禁用弱加密算法,更新TLS版本以保护应用程序免受安全威胁 模块化。JDK 11引入了...

    嵌入式设计及linux驱动开发指南——基于ARM9处理器.pdf

    第6章 Linux系统在ARM平台的移植 6.1 移植的概念 6.2 Linux内核结构 6.3 Linux-2.4内核向ARM平台的移植 6.3.1 根目录 6.3.2 arch目录 6.3.3 arch/arm/boot目录 6.3.4 arch/arm/def-configs目录 6.3.5 arch/...

    java程序设计实验指导代码

    8.4 实验3 字符串的比较和查找最长子串 8.5 实验4 单词逆向输出问题 8.6 实验5 ISBN书号校验问题 第9章 Applet小应用程序 9.1 预备知识 9.2 实验1 Applet生命周期 9.3 实验2 Applet的参数提取 9.4 实验3 鼠标...

    JVM的机制学习手册非常不错

    JVM规范中定义了class文件的格式,JDK在编译java源码时,使用了javac,javac编译的步骤: 1. 分析和输入到符号表(Parse And Enter) Parse做的是词法和语法的分析。 词法分析:将代码字符串转变为token序列 语法...

    学通Java的24堂课

    第7堂课 字符串处理 189 第2部分 提高篇 第8堂课 类的继承与多态特性 219 第9堂课 其他类特性与异常处理 257 第10堂课 swing编程基础 283 第11堂课 多线程编程 319 第12堂课 事件处理的应用 345 第13堂课 ...

    Java典型模块

    19.4 知识点扩展——内存的访问 19.4.1 内存的访问——字节方式 19.4.2 内存的访问——字符和字符串方式 19.5 小结 第20章 日记簿(GUI+文件访问和操作) 20.1 日记簿原理 20.1.1 项目结构框架分析 20.1.2 项目功能...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    4.4.3 字符串编码 115 4.5 查询java api文件 117 4.6 重点复习 119 4.7 课后练习 120 chapter5 对象封装 125 5.1 何谓封装 126 5.1.1 封装对象初始流程 126 5.1.2 封装对象操作流程 128 5.1.3 封装...

    JAVA正则表达式--Pattern和Matcher

    首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经编译后的模式,然后一个Matcher实例在这个给定的Pattern实例的模式­控制下进行字符串的匹配工作。 以下我们就分别来看看这两个类:

    Java JDK正则表达

     正则表达式是Java处理字符串、文本的重要工具。  Java对正则表达式的处理集中在以下两个两个类:  java.util.regex.Matcher 模式类:用来表示一个编译过的正则表达式。  java.util.regex.Pattern 匹配类...

    java学习及java学习代码.rar

    为主方法传递参数“Hello world”字符串,并输出,记录操作过程。 public class Hello { public static void main(String args[]) { System.out.println(“Hello!”); } } (2)分别使用JDK命令行和Eclipse编译Java ...

    java反编译泄露源码-need-for-madness-source:需要疯狂的NFM反编译

    网站、游戏或代码中的字符串没有实际版权,但此代码显然属于 Omar Waly,发布在这里仅供研究之用。 您可能出于非商业个人开源目的阅读、编译、执行和使用/链接代码。 我不认可或希望将此代码用于商业目的,您真的不...

    文本文件(csv、txt等)转excel xlsx小工具(jar包)

    csv是逗号分隔符,该小工具也支持其他分隔符如竖线(|)、井号(#)或其他自定义的字符串。 csv只是文本文件后缀名,也可以是txt或其他后缀名的文本文件。 编译环境jdk1.8 cmd、linux下可运行 自动转换同jar包路径下...

Global site tag (gtag.js) - Google Analytics