Web环境下Java表达式的动态编译与计算

2010-11-07 08:41娄不夜首都经济贸易大学信息学院100070
中国科技信息 2010年16期
关键词:编译器源代码管理器

娄不夜 首都经济贸易大学信息学院 100070

Web环境下Java表达式的动态编译与计算

娄不夜 首都经济贸易大学信息学院 100070

针对Java Web应用程序需要在运行时从外部读得Java表达式并进行计算的要求,利用编译器API对源代码进行编译、采用自定义类装载器装载字节代码、基于反射机制执行字节代码,从而实现Java表达式的动态编译与计算。该方法不需要产生Java源文件或class文件。实际系统的具体应用验证了该方法的有效性。

Java表达式;编译器API;类装载器;反射机制

1. 引言

有些Java Web应用程序在运行时需要从外部(如数据库、XML文件)读入某些数据,以完成相应的处理功能。这些数据可能是一些简单的字符串、数值,也可能是一些需要计算才能得到结果的表达式。

大多数解释型语言都有诸如eval的函数,可以将一个字符串作为表达式进行计算求值,而作为半编译半解释的Java语言并不提供类似的功能。本文介绍一种利用Java SE6提供的编译器API实现类似功能的方法,可以在程序运行过程中完成Java表达式的编译和计算。

2. 基本过程与相关技术

该方法涉及动态编译、自定义类装载器、反射机制等技术,其基本过程如下:

(1) 基于要计算的表达式字符串构建一个Java类,类的源代码存储在普通的字符串中。

(2) 利用编译器API实现对源代码的动态编译。其中源代码直接读自上述字符串,编译产生的字节代码保存在字节数组中。整个过程不涉及源代码文件和字节代码文件的创建。

(3) 使用自定义类装载器装入字节代码、产生Class对象。这里,类装载器直接从字节数组读取字节代码。由于Java不支持类的重新装载,也不允许已装载类的卸载,所以每次计算表达式都需要新建一个类装载器实例。

(4) 利用反射机制调用Temp类的m方法,完成表达式的最后计算。

其中,字符串exp是要计算的表达式,静态方法m的功能是计算并返回表达式的值。这里表达式的类型可以是任意引用类型或基本类型。若是基本类型,计算结果会自动转换成相应包装类对象返回。

3. 动态编译的实现

3.1 动态编译的步骤

(1) 调用javax.tools.ToolProvider类的getSystemJavaCompiler方法获得编译器对象。

(2) 调用编译器对象的getTask方法创建编译作业对象。getTask方法有六个参数,其中第2个参数需指定一个Java文件管理器,在执行编译作业时,系统会自动调用该文件管理器的相关方法获取用于保存编译产生的字节代码的Java文件对象。第4个参数指定编译所需的相关参数。第6个参数需指定包含待编译源代码的Java文件对象。其他三个参数可置为null。

(3) 调用编译作业对象的call方法,执行编译作业。若方法返回true,表示编译成功;否则表示编译失败。

(4) 调用Java文件管理器的相关方法获取保存有字节代码的Java文件对象,然后调用Java文件对象的相关方法获取字节代码。

3.2 Java文件对象

Java文件对象是对Java源代码或Java字节代码的抽象表示。默认情况下,一个Java文件对象表示一个Java源文件或一个class文件。为能表示保存在内存(如字符串、字节数组)的Java源代码或字节代码,需要自定义Java文件对象类。

为清晰之见,对两种Java文件对象类分别进行定义。用于表示源代码的Java文件对象类的代码如下:

在执行编译作业时,系统会自动调用getCharContent方法获得源代码。

用于表示字节代码的Java文件对象类的部分代码如下:

当执行编译作业时,系统会自动调用openOutputStream方法获得一个字节输出流,并通过该字节输出流写出编译产生的字节代码。编译结束后,可以调用getByteCode方法获取字节代码。

3.3 Java文件管理器

Java文件管理器用于管理Java文件对象。在创建编译作业对象时,若第2个参数设置为null,系统将采用一个标准Java文件管理器。在这种情况下,编译产生的字节代码将被保存到相应的class文件中。为实现对特殊Java文件对象的管理,需要自定义Java文件管理器类(省略了构造方法):

这种类型的Java文件管理器可以对JavaFileObjectByteCode型文件对象进行管理。当执行编译作业时,系统会自动调用getJavaFileForOutput方法获得用于保存相应字节代码的文件对象。编译结束后,用户也可以调用该方法获得相同的文件对象。

4. 类装载器与代码执行

4.1 类装载器及其作用

要执行Java字节代码,首先需要由类装载器将其装入JVM。在JVM中,通常存在多个类装载器,每个类装载器负责装载特定位置的class文件。最基本的类装载器包括:

(1) 引导(Bootstrap)类装载器。该装载器属于JVM的一部分,其本身在JVM启动时自行装入。作用有两个:一是装载并创建扩展类装载器和应用程序类装载器;二是需要时装载Java核心类库中的class文件。

(2) 扩展(Extension)类装载器。用于装载java.ext.dirs属性指定位置处的class文件。

(3) 应用程序(Application)类装载器。用于装载java.class.path属性指定位置处的class文件。

其中扩展类装载器代码和应用程序类装载器代码都是Java类,它们都是ClassLoader类子类。

每个类装载器在创建时可以指定一个父类装载器,如扩展类装载器就被指定为应用程序类装载器的父类装载器。装载一个类通常由系统隐含调用类装载器的loadClass(String)方法完成,其过程采用委托模型:首先检查当前类装载器是否已装载该类;若没有,就委托其父类装载器进行装载;若没有父类装载器,则委托引导类装载器进行装载;若上述所有情况都无法定位或装载该类,就调用当前类装载器的findClass(String)方法自行装载。

Web应用环境一般会有更多的类装载器,这些类装载器通常把应用程序类装载器作为父类装载器,它们同样采用上述委托模型进行类的装载。

4.2 自定义类装载器

为了能将由动态编译产生的、保存在字节数组中的Temp类的字节代码装入JVM,需要自定义类装载器类:

这里,loadClass(byte[])方法特用于装载Temp类的字节代码,而Temp类引用的其他类型仍由系统隐含调用定义在超类中的loadClass(String)方法装载,实质上就是委托父类装载器或引导类装载器装载。

只要父类装载器和编译参数(getTask方法的第4个参数)设置得当,Temp类和需要计算的表达式就可以引用任何应用程序能够引用的类型。

4.3 代码执行

装入Temp类的字节代码后,就可以利用反射机制执行其中的静态方法,完成表达式的计算求值:

5. Web环境下的应用举例

这里为基于JSF框架的Web应用设计一个名为Calculator的应用程序范围的托管Bean,其他托管Bean可以调用其calculate(String)方法计算指定的Java表达式:

其中,createSource和execute方法的代码已在前面给出,calculate(String)方法除需调用上面两个方法外,主要是要实现代码的动态编译,其处理过程与相关技术在前面已进行了详细介绍,这里不再赘述。

该托管Bean类还定义了若干有名常量。这些常量在每次计算表达式时都是通用的,可以在构造方法中进行设置。这些常量的作用如下:

compiler:编译器对象。用于创建编译作业对象以及标准Java文件管理器。

sm:标准Java文件管理器。在创建自定义的FileManagerImpl型文件管理器时,应将该标准文件管理器作为参数传递给构造方法。

options:作为编译器对象的getTask方法的第4个参数,可包含一些编译参数。如将classpath参数设为Web应用中WEB-INFclasses目录的实际路径。

parent:装载当前Bean类的类装载器。可作为自定义类装载器的父类装载器。

6. 结束语

本文采用编译器API、自定义类装载器、反射机制等技术实现了Java表达式的动态编译和计算。该方法已在实际系统中得到了验证和应用,具有通用、便捷、性能好等特点,达到了满意的效果。

[1]David Biesack. 使用javax.tools创建动态应用程序[EB/OL]. http://www.ibm.com/ developerworks/cn/java/j-jcomp/#download, 2007-12-24.

[2]James Gosling, Bill Joy. The Java Language Specification Third Edition[M]. Addison Wesley,2005:308-331.

[3]藏旭毅. 浅析J2EE应用服务器的JAVA类装载器[J]. 电脑知识与技术.2007, 3(18):1609-1610.

[4]陈烨,张蓓. JDK1.5类库大全[M]. 北京:清华大学出版社.2005:403-419.

10.3969/j.issn.1001-8972.2010.16.063

首都经济贸易大学教改项目(00790954210333)

娄不夜(1965-),男,副教授,硕士,研究方向为信息技术与信息系统、Web应用。

猜你喜欢
编译器源代码管理器
基于TXL的源代码插桩技术研究
启动Windows11任务管理器的几种方法
应急状态启动磁盘管理器
基于相异编译器的安全计算机平台交叉编译环境设计
运行速度大突破华为《方舟编译器》详解
Windows文件缓冲处理技术概述
软件源代码非公知性司法鉴定方法探析
基于语法和语义结合的源代码精确搜索方法
通用NC代码编译器的设计与实现
基于ARM嵌入式平台的x86译码SOC架构设计