一、背景
利用Java语言编写系统的时候,经常会遇到业务需求的变更而导致修改代码,甚至有些时候还需要修改核心代码(如果整个系统架构设计的不合理的话)。为了避免这种问题,在Java编程的时候,我们应该将易变业务使用脚本语言编写。
Java世界一直在遭受着“异族”的入侵,比如PHP、Ruby、Groovy、JavaScript等,这些入侵者都有一个共同的特征:全是同一类语言——脚本语言,它们都是在运行期间解释执行的。为什么Java这种强编译型的语言会需要这些脚本语言呢?这是因为脚本语言的三大特点:灵活、便捷、简单。
二、脚本语言特征的简述
上一节提出了脚本语言的三大特征,这一节就这三大特征作一个简单的描述。
灵活:脚本语言一般都是动态类型,可以不用声明类型而直接使用,也可以的在运行期间改变类型。
便捷:脚本语言是一种解释型语言,不需要经过编译成二进制代码,也不需要像Java一样生成字节码。它的执行是依靠解释器解释的,因此在运行期间变更代码非常容易,而且不用停止应用。
简单:关于这一特征,只能说只有部分脚本语言适用,比如Groovy,Java程序员若转到Groovy程序语言上,只需要两个小时,看完语法说明,看完Demo即可以适用了,没有太多的技术门槛。
三、Java程序中使用脚本语言
脚本语言的这些特征是Java所没有的,引入脚本语言可以是Java更加强大,于是Java 6开始正式支持脚本语言。但是因为脚本语言的种类比较多,Java开发者也很难确定该支持哪种脚本语言,因而JCP(Java Community Process)提出了JSR223规范,只要符合该规范的脚本语言,都可以在Java平台上运行(该规范对JavaScript是默认支持的)。
四、实例分析
编写一个简单的模型计算公式,用来观察一下脚本语言是如何“拥抱变化”的。
1、编写JS脚本文件:demo.js,将此文件保存在本地的某个目录下。例如,我保存的路径是D:\learn\demo.js
function fomulate(var1,var2){ return var1 * var2 + factor; }
2、编写Java程序:ScriptIntoJava.java,此类用来观察运行结果。
import java.io.FileReader; import java.util.Scanner; import javax.script.Bindings; import javax.script.Invocable; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class ScriptIntoJava { @SuppressWarnings("resource") public static void main(String[] args) throws Exception{ //获取一个JavaScript执行引擎 ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("javascript"); //建立上下文变量 Bindings bind = scriptEngine.createBindings(); bind.put("factor", 1); //绑定上下文,作用域是当前引擎范围 scriptEngine.setBindings(bind, ScriptContext.ENGINE_SCOPE); Scanner input = new Scanner(System.in); while(input.hasNext()){ int first = input.nextInt(); int second = input.nextInt(); System.out.println("输入参数是:" + first + ", " + second); //读取JS脚本文件 scriptEngine.eval(new FileReader("D:/learn/demo.js")); //是否可调用方法 if(scriptEngine instanceof Invocable){ Invocable in = (Invocable)scriptEngine; //执行JS中的函数 Double result = (Double)in.invokeFunction("fomulate", first,second); System.out.println("运算结果:" + result.intValue()); } } } }
3、第一次运行,如下所示:
1
2
输入参数是:1, 2
运算结果:3
其中蓝色的是在控制台输入的参数。
现在,直接修改demo.js中的方法,保持JVM是运行状态,修改后的文件内容如下:
function fomulate(var1,var2){ return var1 * var2 - factor; }
再次,运行一下,如下所示:
1
2
输入参数是:1, 2
运算结果:1
其中蓝色的是在控制台输入的参数。
五、总结
仅仅修改了脚本文件,而Java还是处于JVM运行状态,没有重新启动,就可以得出两种不同的计算结果,这就是脚本语言对系统设计最有利的地方。此处,我用的JDK 1.8,后面的JDK版本是不是还支持这种特性,有待观察。