Spring2.0
JSR-223
实现
方式
根据不同动态语言引擎编写不同的工厂实现类和工具类
JSR-223定义的标准接口及其实现,JDK6提供直接支持
平台
JDK1.4及以上
JDK5及以上
可扩
展性
添加新的工厂实现和工具类;
定义XML元数据Schema、编写相应的解释器实现
可插入的方式加载脚本引擎,JDK级别的多动态语言兼容性
编程
步骤
1.定义Java接口;
2.配置XML元数据;
3.创建bean对象。
1.创建ScriptEngine对象;
2.执行脚本;
3.调用脚本函数或脚本对象。
特性
支持
Spring框架本身提供的包括IoC在内的各项特性;
声明式编程
面向接口的统一编程方法;
需要Java编程获取由表1可以看出,Spring2.0和JSR-223在多个方面具有互补性:
①将JSR-223的可扩展性应用在Spring2.0中,为Spring增加②利用Spring的声明式编程简化JSR-223的编程步骤;
③利用Spring2.0的IoC容器增强动态语言和Java互动能力。
将两者的特性加以结合,将会显着改善Java语言环境中对动态语言的支持能力。
4 使用JSR-223改进Spring的动态语言集成
在Spring中引入JSR-223提供的动态语言框架的目的是为了通过改进Spring2.0的动态语言支持方式,使程序员更方便地实现多种动态语言的支持,从而获取随着JDK5版本的普遍使用,应用JSR-223编程接口将具有基本的平台支持。根据Java对不同动态语言的支持,需要从Java社区的动态语言支持网站[参考]下载JSR-223对特定动态语言支持的参考实现和脚本引擎,并将相关*.jar文件加入环境路径。如使用JDK6版本则默认具有Javascript引擎支持,使用Javascript作为动态语言的话不需要加载额外的jar文件。
4.2 设计模式
从GoF设计模式的构造型模式来看,Spring采用基本的工厂方法模式和IoC的依赖注入能力实现动态语言的支持;JSR-223的静态结构中采用抽象工厂模式,和Spring不同的是这个抽象工厂本身提供了独立于各种动态语言之外的抽象实现,为特定动态语言的工厂对象提供了部分方法的基本实现。在设计模式的层面上两者没有冲突。
4.3 静态结构
图3 采用JSR-223的Spring动态语言支持框架
两者都采用面向接口编程的原则作为实现基础,通过设计一个AbstractScriptFactory的抽象类,在其内部使用JSR-223的编程接口替换各个特定动态语言的引擎接口,从而将Spring的动态语言支持框架与特定引擎解耦。类图如图3所示。
4.4 抽象类的方法的实现
使用JSR-223提供的编程接口和Java的动态代理技术完成ScriptFactory的抽象实现AbstractScriptFactory,在这个类里按照Spring的ScriptFactory接口方法,使用ScriptEngine类型替换生成动态语言对象的工具类。特定动态语言的支持只需要继承这个抽象类,设置动态语言的引擎名称即可,不需要修改Spring本身的可扩展XML元数据配置机制。其中内部类片断如下。
4.5 特定动态语言的支持
使用该改进方案重新实现JRubyScriptFactory,只在构造方法中调用了setEngineName方法设置了引擎名称:
public JRubyScriptFactory(
String scriptSourceLocator, Class[] scriptInterfaces) {
super(scriptSourceLocator, scriptInterfaces);
super.setEngineName("jruby");
}
新的JRubyScriptFactory实现和Spring提供的默认实现相比,编码中除了JRuby的异常类型之外没有对JRuby的显式依赖,代码从需要编写特定的工具类减少到只剩一个构造方法。同时只需在环境路径中加载JSR-223对JRuby的参考实现即可。
按照改进的动态语言支持方案,为Spring2.0添加Javascript支持不需要程序员过多熟悉Rhino引擎的编程接口,只需要根据bean定义的方法调用要求,继承AbstractFactory类并覆盖实现createScriptObject方法,替换Javascript函数的调用方法即可。
4.6 元数据配置
完成以上所需的类文件编写,如果不引入新的动态语言支持,则不需要任何额外的修改;若引入新的动态语言支持,则需要通过修改Spring2.0提供的元数据扩展功能增加动态语言支持的元数据配置命名空间,从而在Spring中以声明的方式实现动态语言集成功能。如增加对Javascript的支持,修改步骤
(1)修改元数据配置的schema文件spring-lang-2.0.xsd
xsd:element
name="Javascript"
type="dynamicScriptType"
xsd:annotation xsd:documentation![CDATA[
A Spring bean backed by a piece of Javascript.
]]/xsd:documentation
/xsd:annotation
/xsd:element
(2)在LangNamespaceHandler类的init方法中注册动态语言的解析器:
public void init(){
if(ClassUtils.isPresent(
"com.sun.script.Javascript.RhinoScriptEngine"))
registerBeanDefinitionParser("Javascript",new ScriptBeanDefinitionParser(JSFactory.class));
...
}
(3)编译并打包:完成类文件和schema文件的修改后,按照可扩展的XML元数据配置要求完成handler和schema的注册,并且编译生成jar文件即可。
5 结束语
5.1 动态语言的特性和IoC的结合
在Java开发中使用动态语言的特性可以显着降低Java编程的规模。如在数据处理中常用的集合类操作,在使用Java编程时java.util.List接口类型只定义了25个实例方法,而Ruby语言中的Array类提供了78个方法。程序员在进行一般的功能性操作时往往更关注于直接能够使用的实例方法,不会使用Spring的IoC容器为动态语言提供了良好的对象边界定义和依赖注入功能。除了Ruby和Groovy等动态语言本身就提供了完整的面向对象支持,其他部分动态语言的面向对象支持能力有限,同时这些动态语言本身的编程风格和语法特性往往被局限在领域内部:如Rhino引擎为Javascript提供了名为E4X的XML操作功能,为Javascript增加了语法层次上的增强。而将这种语法增强移植到Java语言中并不是一件轻易的事。而如果根据需求定义动态语言的接口类型,使用IoC容器注入XMLObject类型的对象(如XML格式的数据结果集)、嵌入Javascript函数就可以在接口类型定义的作用域中使用E4X语法操作XML对象(如图4所示)。
图 4 在Spring实现的Javascript集成中应用E4X特性
5.2 实现Spring与动态语言的可插入方式集成
在没有JSR-223提供的动态语言编程框架之前,Spring2.0版本只能提供有限的动态语言支持,而且随着不同动态语言引擎的版本更新,其中每一个ScriptFactory的实现类都必须进行单独的修改以适应新版本的动态语言引擎。JSR-223的脚本语言编程框架为各种动态语言定义了一致的编程接口,有利于解决多种动态语言的向Java平台的移植和语言本身的向后兼容性,同时扩充了Spring对动态语言支持的静态结构,真正实现Spring对动态语言的可插入方式集成。
参考文献
[1] Martin Fowler. Inversion of Control Containers and the Dependency Injection [EB/OL].
, 2004-01-23
Mike Grogan, JSR-223: Scripting for the JavaTM Platform [EB/OL].
,2006-08-10
Rod Johnson,The Spring Framework – Reference Documentation [EB/OL],
,2007,1
GOF, 李英军. 设计模式[M]. 北京:机械工业出版社,2000