Spring为定义基于动态语言实现的Bean提供了专门的Schema标签,它对应一个专门的命名空间。虽然你也可以使用基于FactoryBean的DTD配置定义动态语言实现的Bean,但这将导致冗长的配置,而且没有隐藏Spring的底层实现细节,Spring强力推荐你采用基于Schema的配置实现。
在采用基于Schema的动态语言配置之前,你必须在Spring配置文件中引入动态语言的命名空间,其配置如下所示:
代码清单 1 引入lang命名空间
<?XML version="1.0" encoding="UTF-8"?>
<beans XMLns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
XMLns:lang="http://www.springframework.org/schema/lang" ①引入动态语言命名空间
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/lang ②指定Schema文件位置
http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
…
</beans>
Spring通过lang命名空间为支持的动态语言提供配置。<lang:jruby>、<lang:groovy>、<lang:bsh>分别对应JRuby、Groovy和BeanShell动态语言。将来Spring还势必对其它一些动态语言提供支持,但这一配置结构可以轻松地进行扩展,所以总体结构是稳定的。
Spring使用JDK动态代理技术为动态语言类生成Java的代理实例,它需要一个Java接口的支持。也就是说,使用动态语言对Java接口提供实现,而Spring将其“翻译”成Java接口的代理实例。
下面,我们先定义一个Java的接口,在本文后面的内容中,我们将通过JRuby对该接口提供实现:
代码清单 2 Java接口
packa攀?畱瑯?? ?o??ūge com.baobaotao.service;
public interface BbtForum {
String getDesc();
}
这个接口很简单,我们不去关心这个接口的功能是否适合动态语言实现,仅希望通过该接口讲解要Spring中使用动态语言的步骤,一旦你掌握了这些基本步骤后,你就可以很容易地实现一些复杂的应用。
基于JRuby的Bean
要在Spring中使用JRuby,必须将jruby.jar和cglib-nodep-2.1_3.jar类包添加到类路径下,你可以在Spring完整发布版本中找到它们。
下面的脚本使用JRuby语言对BbtForum接口提供实现,该脚本文件命名为RubyBbtForum.rb:
代码清单 3 RubyBbtForum.rb:通过JRuby对BbtForum提供实现
require 'Java'
include_class 'com.baobaotao.service.BbtForum'
class RubyBbtForum < BbtForum
def setDesc(desc)
@@desc = desc
end
def getDesc
@@desc;
end
end
RubyBbtForum.new ①实例化并返回RubyBbtForum类实例
注意JRuby源码的最后一行的“RubyMessenger.new”,如①所示,该语句实例化动态语言定义的类并返回对应类的实例。如果你忘记添加该行代码,并不意味着所有努力白费了, Spring将通过反射机制扫描这个JRuby脚本文件,找出一个类并实例化之。如果不提供这一行且Spring无法在JRuby脚本文件中找到可实例化的类,就会抛出ScriptCompilationException异常。
在编写好这个RubyBbtForum.rb脚本文件后,将其放到类路径下。现在我们就可以着手在Spring中使用这个脚本文件,并在Java程序中通过BbtForum接口进行调用了。来看一下具体的配置:
代码清单 4 applicationContext.XML 配置JRuby实现的Bean
…
<lang:jruby id="bbtForum1"
script-interfaces="com.baobaotao.service.BbtForum" ①脚本所实现的Java接口
script-source="classpath:RubyBbtForum.rb"> ②JRuby脚本文件的地址
<lang:property name="desc" value="This is a baby's Forum (jruby) " /> ③注入属性值
</lang:jruby>
…
首先,你必须象代码清单 1一样定义好lang的命名空间,之后你就可以使用<lang:jruby>对JRuby的脚本文件进行配置。①处指定了脚本文件实现的Java接口,多个接口可以用逗号分隔,Spring将JRuby脚本动态代理为实现该接口的实例。在②处,通过script-source属性指定JRuby脚本文件所在的位置,一般情况下将这些脚本文件放到Java的类路径下以便于加载。③处使用<lang:property>为JRuby脚本注入一个配置值,你也可以使用ref属性引用Spring容器中其它Bean。
当在Spring中配置好Ruby实现的Bean中,就可以象Java实现的Bean一样在配置文件其它地方引用该Bean,在程序中调用Bean的方法执行操作——对于调用者来说,根本不知道这个Bean的具体实现技术。我们通过BbtForumTest测试类中对刚才定义的bbtForum1 Bean进行测试:
代码清单 5 BbtForumTest:测试JRuby实现的Bean
package com.baobaotao.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXMLApplicationContext;
import com.baobaotao.service.BbtForum;
public class BbtForumTest {
public static void main(String[] args) {
String config = "applicationContext.XML";
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.XML");
BbtForum bbtForum = (BbtForum) ctx.getBean("bbtForum1"); ①获取JRuby实现的Bean
System.out.println(bbtForum.getDesc()); ②按正常的方式进行访问
}
}
运行以上代码,将正确输出以下的信息:
This is a baby's Forum (jruby)
可见,在Spring配置文件中注入的属性值正确应用到JRuby实现的Bean中,并且可以通过BbtForum接口方法正确调用JRuby脚本的功能。