jruby的好处是可以同时利用ruby和java这两大社区的积累,那么我们怎么在ruby代码中装载java资源呢。
装载java资源之前,先要require一下java,否则后续会有一些功能不能执行。
jruby-1.5.6 :001 > require 'java'
=> true
下面具体进行装载,首先是load相关的jar文件,jruby进程本质上就是jvm进程,所以可以直接指定启动jvm时的classpath。
当然,我们还可以用代码来动态的完成这个工作:
jruby-1.5.6 :002 > require 'java/jars/commons-logging-1.1.1.jar'
=> true
jruby-1.5.6 :003 > require 'java/jars/spring-2.5.6.jar'
=> true
对于类装载而言,还有一种情况,就是没有打包为jar的那些class文件,java的做法是在classpath中设置,jruby对此也提供了动态载入的方式
003 > $CLASSPATH << "java/conf/"
=> ["file:java/conf/"]
接下来就可以直接使用了
jruby-1.5.6 :004 > puts org.springframework.context.support.ClassPathXmlApplicationContext
Java::OrgSpringframeworkContextSupport::ClassPathXmlApplicationContext
=> nil
显然,在jruby中,普通的java类被装载到了用模块组织的命名空间中,如果需要简化使用,可以这样:
jruby-1.5.6 :005 > include Java::OrgSpringframeworkContextSupport
=> Object
然后可以简化代码
jruby-1.5.6 :006 > puts ClassPathXmlApplicationContext.class
Class
jruby-1.5.6 :007 > puts ClassPathXmlApplicationContext.new
org.springframework.context.support.ClassPathXmlApplicationContext@4b0613aa: display name
[org.springframework.context.support.ClassPathXmlApplicationContext@4b0613aa]; startup date
[Thu Jan 01 08:00:00 CST 1970]; root of context hierarchy
当然,如果你对java更熟悉,那么也可以用更java的方式做这件事
jruby-1.5.6 :008 > java_import java.lang.System
=> Java::JavaLang::System
jruby-1.5.6 :009 > puts System.class
Class
=> nil
但是这种方法不能导入一个包,因为 java.lang.System 不是一个对象,所以有一个 include_package 方法
jruby-1.5.6 :010 > include_package 'java.lang'
NoMethodError: undefined method `include_package' for #<Object:0x7023d08b>
from (irb):10
jruby-1.5.6 :011 > module X
jruby-1.5.6 :012 > include_package 'java.lang'
jruby-1.5.6 :013 > end
jruby-1.5.6 :014 > puts X::Long
Java::JavaLang::Long
=> nil
也许你注意到了,使用include_package需要在一个module中,因为include_package这个方法是定义在核心库的Module类中的,我猜这么做是为了防止命名空间污染(有兴趣的同学可以看看Module类的源码,里面有 const_missing 相关的代码)
类资源装载大致就是这样,当然,这些都是在同一个classloader中,其实个人认为,有了ruby的动态能力支持和module作为作用域空间,classloader这种东西可以尽量少用了
更多了解,可以看看 https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby
最后说明一下,混合语言编程并不是个好主意,那样代码会比较难以维护。比较好的方式是,首先划清界限,然后在ruby中引入java服务接口,这是一种既可行又好用的方法。